## 07-使用 async void 方法 ```csharp /// <summary> /// 使用 async void 方法 /// </summary> /// <param name="args"></param> static void Main(string[] args) { // 使用 async Task 可以通过返回值的Task示例,监控任务的状态 Task t = AsyncTask(); t.Wait(); // 使用 async void 没有返回值,无法监控任务状态 AsyncVoid(); // 这里使用Sleep方法确保任务完成 Thread.Sleep(TimeSpan.FromSeconds(3)); // 根据Task.IsFaulted属性可以判断是否发生异常 // 捕获的异常信息可以从Task.Exception中获取 t = AsyncTaskWithErrors(); while (!t.IsFaulted) { Thread.Sleep(TimeSpan.FromSeconds(1)); } Console.WriteLine(t.Exception); // 该段代码虽然使用try/catch捕获异常,但是由于使用了 async void 方法, // 异常处理方法会被放置到当前的同步上下文中(即线程池的线程中)。 // 线程池中未被处理的异常会终止整个进程。 //try //{ // AsyncVoidWithErrors(); // Thread.Sleep(TimeSpan.FromSeconds(3)); //} //catch (Exception ex) //{ // Console.WriteLine(ex); //} // Action类型也是可以使用 async 关键字的; // 在lambda表达式中很容易忘记对异常的处理,而这会导致程序崩溃。 int[] numbers = { 1, 2, 3, 4, 5 }; Array.ForEach(numbers, async number => { await Task.Delay(TimeSpan.FromSeconds(1)); if (number == 3) { throw new Exception("Boom!"); } Console.WriteLine(number); }); Console.ReadLine(); } static async Task AsyncTaskWithErrors() { string result = await GetInfoAsync("AsyncTaskException", 2); Console.WriteLine(result); } static async void AsyncVoidWithErrors() { string result = await GetInfoAsync("AsyncVoidException", 2); Console.WriteLine(result); } static async Task AsyncTask() { string result = await GetInfoAsync("AsyncTask", 2); Console.WriteLine(result); } static async void AsyncVoid() { string result = await GetInfoAsync("AsyncVoid", 2); Console.WriteLine(result); } static async Task<string> GetInfoAsync(string name, int seconds) { await Task.Delay(TimeSpan.FromSeconds(seconds)); if (name.Contains("Exception")) { throw new Exception($"Boom from {name}"); } return $"Task {name} is running on a thrad id {Thread.CurrentThread.ManagedThreadId}. " + $"Is thread pool thread: {Thread.CurrentThread.IsThreadPoolThread}"; } ``` 运行结果: ``` Task AsyncTask is running on a thrad id 4. Is thread pool thread: True Task AsyncVoid is running on a thrad id 4. Is thread pool thread: True System.AggregateException: 发生一个或多个错误。 ---> System.Exception: Boom from AsyncTaskException 在 Recipe5_7.Program.<GetInfoAsync>d__5.MoveNext() 位置 C:\Users\liujiajia\So urce\Repos\learn-multi-threading\Recipe5-7\Program.cs:行号 88 --- 引发异常的上一位置中堆栈跟踪的末尾 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNot ification(Task task) 在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() 在 Recipe5_7.Program.<AsyncTaskWithErrors>d__1.MoveNext() 位置 C:\Users\liuji ajia\Source\Repos\learn-multi-threading\Recipe5-7\Program.cs:行号 61 --- 内部异常堆栈跟踪的结尾 --- ---> (内部异常 #0) System.Exception: Boom from AsyncTaskException 在 Recipe5_7.Program.<GetInfoAsync>d__5.MoveNext() 位置 C:\Users\liujiajia\So urce\Repos\learn-multi-threading\Recipe5-7\Program.cs:行号 88 --- 引发异常的上一位置中堆栈跟踪的末尾 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNot ification(Task task) 在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() 在 Recipe5_7.Program.<AsyncTaskWithErrors>d__1.MoveNext() 位置 C:\Users\liuji ajia\Source\Repos\learn-multi-threading\Recipe5-7\Program.cs:行号 61<--- 5 2 1 4 未经处理的异常: System.Exception: Boom! 在 Recipe5_7.Program.<>c.<<Main>b__0_0>d.MoveNext() 位置 C:\Users\liujiajia\S ource\Repos\learn-multi-threading\Recipe5-7\Program.cs:行号 51 --- 引发异常的上一位置中堆栈跟踪的末尾 --- 在 System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__ 6_1(Object state) 在 System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object sta te) 在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionCo ntext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, C ontextCallback callback, Object state, Boolean preserveSyncCtx) 在 System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWor kItem.ExecuteWorkItem() 在 System.Threading.ThreadPoolWorkQueue.Dispatch() 在 System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() ``` 放开main方法中间的备注代码,会发生如下异常: ``` 未经处理的异常: System.Exception: Boom from AsyncVoidException 在 Recipe5_7.Program.<GetInfoAsync>d__5.MoveNext() 位置 C:\Users\liujiajia\So urce\Repos\learn-multi-threading\Recipe5-7\Program.cs:行号 89 --- 引发异常的上一位置中堆栈跟踪的末尾 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNot ification(Task task) 在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() 在 Recipe5_7.Program.<AsyncVoidWithErrors>d__2.MoveNext() 位置 C:\Users\liuji ajia\Source\Repos\learn-multi-threading\Recipe5-7\Program.cs:行号 68 --- 引发异常的上一位置中堆栈跟踪的末尾 --- 在 System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__ 6_1(Object state) 在 System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object sta te) 在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionCo ntext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, C ontextCallback callback, Object state, Boolean preserveSyncCtx) 在 System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWor kItem.ExecuteWorkItem() 在 System.Threading.ThreadPoolWorkQueue.Dispatch() 在 System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() ``` **强烈建议只在UI事件处理器中使用 async void 方法。在其它所有的情况下,请使用返回 Task 的方法。** Loading... 版权声明:本文为博主「佳佳」的原创文章,遵循 CC 4.0 BY-NC-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://www.liujiajia.me/2017/8/8/csharp-multi-threading-05-csharp6-07-async-void 提交