4

我试图围绕 C# 中并行任务的一些语法和结构,特别是链接多个任务处理错误

我要创建的具体步骤顺序是:

  • 生成一个并行任务并立即返回 UI。
  • 在并行任务中:
    • Process1()
    • 如果Process1()完成没有错误,请执行Process2()
    • 如果Process2()完成没有错误,请执行Process3()
    • 如果所有任务都完成且没有错误,请执行SuccessCondition()
    • 如果任何任务导致错误,请执行ErrorCondition()

我的理解是,我将创建一个Task并调用ContinueWith()以链接更多任务,传入一个TaskContinuationOptions标志以确定何时执行该继续。此外,成功/错误条件将贯穿所有延续到最后。所以我目前正在尝试这个:

var task = new Task(() => Process1());
var task2 = task.ContinueWith(t => Process2(), TaskContinuationOptions.OnlyOnRanToCompletion);
var task3 = task2.ContinueWith(t => Process3(), TaskContinuationOptions.OnlyOnRanToCompletion);
var task4 = task3.ContinueWith(t => SuccessCondition(t), TaskContinuationOptions.OnlyOnRanToCompletion);
var task5 = task4.ContinueWith(t => ErrorCondition(t), TaskContinuationOptions.NotOnRanToCompletion);
task.Start();

ErrorCondition()它的行为似乎符合预期,除了tProcess2(). 查看处理异常的 MSDN 文章,它说要这样做:

try
{
    task.Wait();
}
catch (AggregateException ex)
{
    // Handle exceptions from a collection on ex
}

但是,我试过了,它似乎也没有例外。另外,通过这样调用.Wait()主线程,我是否否定了并行性并只是阻塞了?在我的测试中看起来就是这样。

所以我想我的问题是......链接相关任务并在这里处理整体成功/错误条件的正确方法是什么?或者,应该如何正确捕获从这些任务中抛出的异常,同时仍立即返回 UI?

4

2 回答 2

4

请注意,如果您使用的是 .NET 4.5 并且可以使用 async/await,则可以更干净地执行此操作:

    public async Task DoProcess()
    {
        try
        {
            await Task.Run(Process1);
            await Task.Run(Process2);
            await Task.Run(Process3);
            SuccessCondition();
        }
        catch (Exception ex)
        {
            ErrorCondition(ex);
        }
    }

如果从 UI 线程启动它,UI 线程上也会发生 SuccessCondition 和 ErrorCondition。这里的一个功能区别是您捕获的异常不会是 AggregateException;相反,它将是在等待调用失败期间引发的实际异常。

于 2013-06-14T19:00:48.663 回答
3

您需要为所有任务 1-4 添加一个延续,并带有错误处理案例,以允许其中任何一个错误调用该函数。

为方便起见,您可以创建一个方法来将相同的延续添加到任务集合中。这是一个(可以根据需要为 ContinueWith 的其他重载添加其他内容):

public static IEnumerable<Task> ContinueWith(this IEnumerable<Task> tasks
    , Action<Task> continuation, TaskContinuationOptions options)
{
    return tasks.Select(task => task.ContinueWith(continuation, options))
        .ToList();//important for this ToList to be here; 
    //we want the continuations to be added now, not when the result is iterated
}

这允许您编写:

var errorTasks = new[]{task, task2, task3, task4}
    .ContinueWith(ErrorCondition, TaskContinuationOptions.NotOnRanToCompletion); 

async不过,使用方法在 C# 5.0 中对任务的错误处理变得非常容易。它将允许您将代码转换为:

public static async Task Foo()
{
    try
    {
        await Task.Run(Process1())
        await Task.Run(Process2())
        await Task.Run(Process3())
        SuccessCondition();
    }
    catch (SomeExceptionType ex)
    {
        HandleException(ex);
    }
}

这个功能就像您认为它根据您的要求所做的那样,这太棒了。

于 2013-06-14T18:52:23.813 回答