创建表示一系列延续任务的任务

时间:2012-04-15 10:18:12

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

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

public Task Refresh();  

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

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

    return ?;
}  

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

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

当然,使用TPL有一种简洁有效的方法吗?

2 个答案:

答案 0 :(得分:3)

通常,Task.Status仅用于了解最终状态。无论如何,你不能依赖任务[{1}}因为该状态可能随时改变。

由于这个事实,你返回的任务在完成之前是否具有“奇怪”状态并不重要。只有三个已完成的状态(StartedCompletedCanceled)很重要。

答案 1 :(得分:0)

我做了一些进一步的研究,发现了类似的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

所以有一半的答案 - 您可以创建一个代表所有子任务的Task实例,而无需假脱机线程并将它们作为子任务附加:只需使用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(如果处理了这些情况,则为Faulted / Cancelled)。