0%

Async Await DeadLock問題

之前寫了一個簡單上傳圖片的功能,碰到用await跟async非同執行的問題,本來在本機Visual Studio偵錯執行Run都好好的,但是放到線上後就永遠得不到回應TimeOut

隱隱約約記得之前黑大寫過類似的文章,當時看過沒啥特別感覺,翻回來看後在實際操作後終於弄懂了(果然寫程式很多地方一知半解會GG的),關於Async、Await這些推薦可以看這兩篇文章

Huan-Lin 學習筆記-async 與 await
黑暗執行緒- await與Task.Result/Task.Wait()的Deadlock問題

兩位前輩大大已經寫的很完整詳盡了,在這邊就不獻醜了,只簡單提供個範例給有興趣的人玩玩

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class DeadLockController : ApiController
{
[HttpGet]
[Route("api/DeadLock/Index")]
public HttpResponseMessage Index()
{
Task<int> mytask = Go();
mytask.Wait();
return Request.CreateResponse(mytask.Result);
}

[HttpGet]
[Route("api/DeadLock")]
public HttpResponseMessage DeadLock()
{
var result = Go().Result;
return Request.CreateResponse(result);
}

[HttpGet]
[Route("api/DeadLock/NoDeadLock")]
public async Task<HttpResponseMessage> NoDeadLock()
{
var result = await Go();
return Request.CreateResponse(result);
}

private async Task<int> Go()
{
int res = 0;
await Task.Run(() =>
{
//假裝執行某個耗時程序後取得結果
Task.Delay(1000);
res = 32767;
});
return res;
}
}

這邊只有NoDeadLock那個Action的寫法才不會DeadLock,其餘兩個永遠都不會得到回應,原因簡單的說就是在Web中**(特別強調在Web中,因為Console並不會)**,.Result 與 Wait()的方法都會鎖定目前的Thread等待結果回應再繼續執行,而上面的範例GO()這個Method在Web中會記住是哪個Thread來呼叫他的,以便他執行完後回應該Thread結果繼續執行。

這時候就會發生DeadLock了,因為外面用Wait() or .Result鎖住當前Thread,GO()這個Method又在等待他被釋放好跟他回應結果,互相等待也就DeadLock了。

前面兩篇文章很久以前就看過了,只是當時沒有特別放在心上,直到被這個簡單到只有5行Code的東西困擾了3~4天,才終於想到有這件事情,現在不懂沒關係,等到被鎖一次就懂了(吶喊!!)