将并行任务链接到结束条件或错误条件
本文关键字:条件 错误条件 结束 并行任务 链接 | 更新日期: 2023-09-27 18:18:22
我正在努力了解c#中并行任务的一些语法和结构,特别是链接多个任务和处理错误。
我希望创建的具体步骤顺序是:
- 生成一个并行任务并立即返回UI。
- 并行任务中:
- Do
Process1()
- 如果
Process1()
没有错误完成,则执行Process2()
- 如果
Process2()
完成无误,则执行Process3()
- 如果所有任务顺利完成,执行
SuccessCondition()
- 如果任何任务导致错误,执行
ErrorCondition()
- Do
我的理解是,我会创建一个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()
中t
的实例似乎没有异常,即使我手动从Process2()
中抛出一个异常。查看MSDN关于处理异常的文章,它说要这样做:
try
{
task.Wait();
}
catch (AggregateException ex)
{
// Handle exceptions from a collection on ex
}
然而,我试过了,它似乎也没有例外。此外,通过在主线程中调用.Wait()
,我否定并行性,只是阻塞吗?在我的测试中似乎是这样的。
请注意,如果您使用的是。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线程中启动这个,那么SuccessCondition和ErrorCondition也会在UI线程中发生。这里的一个功能区别是,您捕获的异常将不是AggregateException;它将是等待调用失败时抛出的实际异常。
您需要添加一个延续到所有的任务,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);
在c# 5.0中,通过async
方法,任务的错误处理变得更加容易。它允许你将代码转换成这样:
public static async Task Foo()
{
try
{
await Task.Run(Process1())
await Task.Run(Process2())
await Task.Run(Process3())
SuccessCondition();
}
catch (SomeExceptionType ex)
{
HandleException(ex);
}
}
这个功能就像你想象的那样,根据你的要求,这是很棒的。