C# 多线程 05-使用 C#6.0 07-使用 async void 方法
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}";
}
运行结果
txt
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()
TIP
强烈建议只在 UI 事件处理器中使用 async void
方法。在其它所有的情况下,请使用返回 Task
的方法。