码迷,mamicode.com
首页 > Web开发 > 详细

.Net异步编程进阶之(二)

时间:2018-11-19 14:07:00      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:启动   没有   出现   something   code   service   wpf   中断   mic   

  避免使用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.ContinueWithawait 并不是语法上不一样而已,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异步编程进阶之(二)

标签:启动   没有   出现   something   code   service   wpf   中断   mic   

原文地址:https://www.cnblogs.com/zigit/p/9939858.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!