【问题标题】:Creating a Task that represents a series of continuation tasks创建一个代表一系列后续任务的任务
【发布时间】:2014-04-13 00:50:12
【问题描述】:

例如,假设我正在编写一个具有以下签名的方法(C#4 所以没有异步关键字):

public Task Refresh();  

它将调用一个方法(也返回一个Task)来执行通信工作,然后运行一个任务继续以根据检索到的数据更新一些内部状态。例如:

public Task Refresh()
{
    Task<MyData> commsTask = datasource.LoadData();
    Task handleDataTask = commsTask.ContinueWith( HandleNewData );

    return ?;
}  

如果我返回 handleDataTask,它的完成状态会正确跟踪“刷新”操作的结果,但它不会正确报告它的启动状态。

我可以将两者都包装在一个新的 Task.Factory.StartNew 中并将它们创建为子任务,但是为了链接一些任务延续而设置一个新线程似乎很浪费。

肯定有一种简洁有效的方法可以用 TPL 做到这一点吗?

【问题讨论】:

  • 为什么要关心国家?
  • 这样实现匹配方法签名的隐式文档?我不知道,问我方法的消费者。 Task.Status 属性可能有 100 种可能的用途,我所知道的是我的方法应该返回一个正确遵循其文档的 Task

标签: c# .net-4.0 task-parallel-library


【解决方案1】:

通常,Task.Status 仅用于了解最终状态。无论如何,您不能依赖任务蜂鸣 Started,因为该状态随时可能改变。

因此,您返回的任务在完成之前是否处于“奇怪”状态并不重要。只有三个完成状态(CompletedCanceledFaulted)很重要。

【讨论】:

  • 我同意 3 个最终状态很重要。但是不能保证最终任务会运行,因此通过返回链中的最终任务,您可能会冒着使您返回的代表整个操作的“任务”实例永远卡在WaitingForActivation 中的风险。我没有在示例中包含它,但是如果取消了先前的任务,则任务继续可能不会运行。
  • @Tyson,如果前面的任务被取消,后续任务通常会运行。如果您使用TaskContinuationOptions 来修改它,则继续也会被取消。因此,它不会卡在WaitingForActivation 状态(除非前件包含无限循环或死锁)。
  • @svick 嗯...我现在找不到参考,但我确实记得看到一个任务继续没有运行的例子。虽然现在我在想,虽然它没有运行,但它仍然像你说的那样直接转换到 Cancelled 状态。不知道,返回final task代表整个序列还是感觉很乱。
  • 任务应该是对如何计算结果的完全抽象。从这个意义上说,这个模型是完全干净的。
【解决方案2】:

我做了一些进一步的研究,发现了一个类似的 SO 问题,以及一些博客文章:

Task chaining without TaskCompletionSource?

http://blogs.msdn.com/b/pfxteam/archive/2010/11/21/10094564.aspx

http://msmvps.com/blogs/jon_skeet/archive/2011/05/20/eduasync-part-7-generated-code-from-a-simple-async-method.aspx

所以只有一半的答案 - 您可以创建一个代表所有子任务的任务实例,而无需假脱机一个新线程并将它们作为子任务附加:只需使用 TaskCompletionSource。下面的简单示例适用于我上面的问题,没有失败或取消处理:

public Task Refresh()
{
    var refreshTaskSource = new TaskCompletionSource<object>();

    Task<MyData> commsTask = datasource.LoadData();
    Task handleDataTask = commsTask.ContinueWith( HandleNewData );
    handleDataTask.ContinueWith( t => refreshTaskSource.SetResult(null) );

    return refreshTaskSource.Task;
} 

但是此方法返回的任务现在直接从 TaskStatus.WaitingForActivation 转换为 TaskStatus.RanToCompletion(如果我处理过这些情况,则为故障/取消)。

【讨论】:

    猜你喜欢
    • 2021-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 2018-04-15
    • 1970-01-01
    • 2013-01-20
    • 1970-01-01
    相关资源
    最近更新 更多