如何安排条件ContinueWith

时间:2011-10-24 08:17:56

标签: c# c#-4.0 asynchronous task-parallel-library continuations

我在一堆LINQ查询上有一些GUI。查询需要一些时间来执行,所以我希望GUI能够响应并显示busyindicators和进度条。许多查询都是检查数据中存在的某些条件。如果查询返回空结果,则应用程序将继续下一个查询。如果它返回结果,则返回集将具有严重性"警告"或"错误"。如果是警告,则继续执行。如果是错误,它将停止。

许多代码播放"乒乓球"使用线程池和GUI。准码:

TaskFactory.StartNew(()=>
    {
       Run in background
    }.ContinueInGui(()=>
    {
       Update something
    }).ContinueInBackground(()=>
    {
      Do more work;
    }).ContinueInGui(()=> etc etc

这很整洁。但是,如果在数据中发现错误,我不知道如何插入条件来执行不同的延续路线或中断连续链。

没有ContinueWithIf方法(谓词,委托{},TaskScheduler) 我是否使用TaskCancellation,是否会抛出异常?或者是否有一些我没想过的简单分支机制?

2 个答案:

答案 0 :(得分:9)

这里的一个好选择是使用CancelationTokenSource,如果你想“破坏”你的连续链,只需将其标记为取消。通过在ContinueWith中添加TaskContinuationOptions.NotOnCanceled作为后续任务,您可以通过将CancelationTokenSource标记为已取消来随时安排这些任务。

如果你真的想使用谓词,而不是在main方法中设置continuation,你需要制作一个自定义方法来为你处理这个问题。这可以通过使用附加延续的扩展方法来完成 - 延续可以检查谓词,并在适当时触发连续。这看起来像是:

public static Task ContinueWithIf(this Task task, Func<bool> predicate, Action<Task> continuation, TaskScheduler scheduler)
{
    var tcs = new TaskCompletionSource<object>(); 

    task.ContinueWith( t =>
    {
        if (predicate())
        {
            new TaskFactory(scheduler).StartNew( 
                () => 
                {
                    continuation(task); 
                    tcs.SetResult(null); 
                });
        }
        else
        {
            tcs.TrySetCanceled();
        }
    });

    return tcs.Task;
}

当然,你可能想要为Task<T>创建一个版本,以及处理任务上的故障/取消状态。话虽如此,它应该正常运作。

答案 1 :(得分:4)

如果有错误,您应该考虑相应地使您的任务出错。然后,您可以在ContinueWith来电中使用TaskContinuationOptions.OnlyOnRanToCompletion等。

基本上,在任务结束时有三种可能的状态:

  • RanToCompletion
  • 取消
  • 断陷

你可以让ContinueWith适用于这些状态的任何合理组合,如果你想根据错误与成功和取消等做不同的事情,你可以为同一个父任务附加不同的延续。