避免使用Task.Result和Task.Wait
只有极少方法可以正确的使用Task.Result和Task.Wait,一般情况下建议是完全避免在代码上出现。
同步异步
这里说的同步异步是指把异步操作通过Task.Result或Task.Wait阻塞线程转为同步,使用Task.Result和Task.Wait阻塞等待异步操作比起真正调用同步操作的API要糟糕的多,下面是经常发生的情况。
- 启动异步操作
- 阻塞调用线程等待操作结果
- 当异步操作完成时,继续执行等待操作的代码。
结果就是使用了2个线程来完成了只需要1个线程即可完成的同步操作,这往往会导致线程池饥饿最终导致服务中断。
死锁
在ASP.NET (Web Forms)、Windows Forms、WPF、UWP的UI线程上如果使用Task.Result和Task.Wait都会导致死锁。因为这些程序的UI都是单线程的,这些程序会在构造函数里会把UI线程的Task的同步上下文设置为SynchronizationContext的实例。如果UI线程出现阻塞,Task会在完成任务时候把等待UI线程Task的SynchronizationContext实例用来同步上下文,但UI线程又在等待Task完成,结果就导致死锁。由于这个原因,“聪明”的开发者想出了各种办法试图阻塞线程得到结果。事实上,阻塞异步任务并没有什么好方法。
注意:ASP.NET Core 并没有SynchronizationContext,所以并不容易出现死锁问题。
有时候开发人员会编写的一些"巧妙"的代码去试图避免死锁去同步异步
1 public string DoOperationBlocking() 2 { 3 ????return Task.Run(() => DoAsyncOperation()).Result; 4 } 5 ?6 public string DoOperationBlocking2() 7 { 8 ????return Task.Run(() => DoAsyncOperation()).GetAwaiter().GetResult(); 9 }10 11 public string DoOperationBlocking3()12 {13 ????return Task.Run(() => DoAsyncOperation().Result).Result;14 }15 16 public string DoOperationBlocking4()17 {18 ????return Task.Run(() => DoAsyncOperation().GetAwaiter().GetResult()).GetAwaiter().GetResult();19 }20 21 public string DoOperationBlocking5()22 {23 ????return DoAsyncOperation().Result;24 }25 26 public string DoOperationBlocking6()27 {28 ????return DoAsyncOperation().GetAwaiter().GetResult();29 }30 31 public string DoOperationBlocking7()32 {33 ????var task = DoAsyncOperation();34 ????task.Wait();35 ????return task.GetAwaiter().GetResult();36 }
使用await取代Task.ContinueWith
在引入async / await 之前 Task已经存在了不依赖于语言关键字的函数 Task.ContinueWith 就是其中一个,虽然这些方法仍然可以使用,但我通常还是建议你使用 await 而不是Task.ContinueWith,事实上,Task.ContinueWith 和 await 并不是语法上不一样而已,Task.ContinueWith 不会保存任何类型的状态( ExecutionContext / SynchronizationContext ),如果没有提供回调,则默认会回到原来的线程上继续下接下来的操作。await 关键字则会在Task完成的时候保存状态到当前的线程然后再继续接下来的操作。
这个案例使用的是 Task.ContinueWith 而不是 await
1 public Task<int> DoSomethingAsync()2 {3 ????return CallDependencyAsync().ContinueWith(task =>4 ????{5 ????????return task.Result + 1;6 ????});7 }
这个案例使用关键字 await 获取异步结果
1 public async Task<int> DoSomethingAsync()2 {3 ????var result = await CallDependencyAsync();4 ????return result + 1;5 }
.Net异步编程进阶之(二)
原文地址:https://www.cnblogs.com/zigit/p/9939858.html