使用带有条件延续的任务
我对如何使用条件连续的任务有点困惑。
如果我有一个任务,然后我想继续处理成功和错误的任务,然后等待那些完成。
void FunctionThrows() {throw new Exception("faulted");} static void MyTest() { var taskThrows = Task.Factory.StartNew(() => FunctionThrows()); var onSuccess = taskThrows.ContinueWith( prev => Console.WriteLine("success"), TaskContinuationOptions.OnlyOnRanToCompleted); var onError = taskThrows.ContinueWith( prev => Console.WriteLine(prev.Exception), TaskContinuationOptions.OnlyOnFaulted); //so far, so good //this throws because onSuccess was cancelled before it was started Task.WaitAll(onSuccess, onError); }
这是执行任务成功/失败分支的首选方式吗? 另外,我应该如何加入所有这些任务,假设我已经创建了一长串的延续,每个都有自己的error handling。
//for example var task1 = Task.Factory.StartNew(() => ...) var task1Error = task1.ContinueWith( //on faulted var task2 = task1.ContinueWith( //on success var task2Error = task2.ContinueWith( //on faulted var task3 = task2.ContinueWith( //on success //etc
在这些上调用WaitAll
总是抛出,因为一些延续将由于TaskContinuationOptions
而被取消,并且在取消的任务上调用Wait
会抛出。 如何在没有获得“任务被取消”exception的情况下加入这些例外“?
我认为你的主要问题是你要告诉这两个任务“等待”你的电话
Task.WaitAll(onSuccess, onError);
将自动为您设置onSuccess和onError延续,并将在其前期任务完成后执行。
如果你只是用Task.WaitAll(...)
替换你的Task.WaitAll(...)
taskThrows.Start();
我相信你会得到所需的输出。
这是我放在一起的一个例子:
class Program { static int DivideBy(int divisor) { Thread.Sleep(2000); return 10 / divisor; } static void Main(string[] args) { const int value = 0; var exceptionTask = new Task(() => DivideBy(value)); exceptionTask.ContinueWith(result => Console.WriteLine("Faulted ..."), TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.AttachedToParent); exceptionTask.ContinueWith(result => Console.WriteLine("Success ..."), TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.AttachedToParent); exceptionTask.Start(); try { exceptionTask.Wait(); } catch (AggregateException ex) { Console.WriteLine("Exception: {0}", ex.InnerException.Message); } Console.WriteLine("Press to continue ..."); Console.ReadLine(); } }
使用Task.WaitAny(onSuccess, onError);
这不正常吗?
看看MSDN文档,你做得很好,你正在实现的逻辑是合理的。 您唯一缺少的是将WaitAll调用包装在AggregateException包装中,如下所示:
// Exceptions thrown by tasks will be propagated to the main thread // while it waits for the tasks. The actual exceptions will be wrapped in AggregateException. try { // Wait for all the tasks to finish. Task.WaitAll(tasks); // We should never get to this point Console.WriteLine("WaitAll() has not thrown exceptions. THIS WAS NOT EXPECTED."); } catch (AggregateException e) { Console.WriteLine("\nThe following exceptions have been thrown by WaitAll(): (THIS WAS EXPECTED)"); for (int j = 0; j < e.InnerExceptions.Count; j++) { Console.WriteLine("\n-------------------------------------------------\n{0}", e.InnerExceptions[j].ToString()); } }
你可以在这里阅读更多: http : //msdn.microsoft.com/en-us/library/dd270695.aspx
本质上,捕获AggregatedException会使您完成WaitAll的相同操作。 它是从您的任务返回的所有exception的集合。
- c#MemoryMappedFile in .net 3.5
- 如何在WebClient.DownloadFileAsync上实现超时
- 在可能未初始化的Dictionary元素上执行加号等于操作的简洁方法
- 从ResourceDictionary设置WindowStartupLocation会抛出XamlParseException
- .Equals中c#generics方法中的意外行为
- 如何从C#中的QueryPerformanceCounter获取刻度?
- ListBox的简单WPF DataBinding到字符串的ObservableCollection
- 我可以为此方案设计任何无锁解决方案
- 使用reflection从元数据类中获取属性属性