概述
await/async 關鍵字組合是C#中異步實現的一種常用方式。
async
用於修飾方法,表明該方法爲異步方法。但只有async+await
的組合才能真正實現異步的執行。若“異步方法”內沒有await
,則該方法不是異步方法,仍爲同步模式。- 由於
await
只能用於異步方法中,所以方法必須用async
修飾。 - 異步方法的放回類型必須爲
void
或Task
或Task<TResult>
中的一種。 - 異步方法內必須含有
await
,用於表示異步等待的位置。雖然不太恰當,但有點類似debug中的斷點。 await
後只能修飾Task
或Task<TResult>
。(方法的返回類型或變量類型)await task
的內容等價於task.Result
。await
關鍵字上下的代碼有可能處於不同的線程。
說的挺清楚,就是示例代碼命名有點長有點繞。
https://www.cnblogs.com/zhaoshujie/p/11192036.html
https://www.cnblogs.com/zhili/archive/2013/05/15/Csharp5asyncandawait.html
死鎖
public class AsyncDemo
{
public async void Run()
{
Console.WriteLine($"Demo start\t{Thread.CurrentThread.ManagedThreadId}");
var task = GetAsync();
// await task; // 取消註釋則無死鎖
string ret = task.Result; // 死鎖位置A
Console.WriteLine($"Demo end\t{Thread.CurrentThread.ManagedThreadId}");
}
public async Task<string> GetAsync()
{
Console.WriteLine($"GetAsync start\t{Thread.CurrentThread.ManagedThreadId}");
var task = await Task.Run(() =>
{
Console.WriteLine($"Task start\t{Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(2000);
Console.WriteLine($"Task end\t{Thread.CurrentThread.ManagedThreadId}");
return "xxxx";
});// 死鎖位置B
Console.WriteLine($"GetAsync end\t{Thread.CurrentThread.ManagedThreadId}");
return task;
}
}
死鎖狀態
取消註釋後
死鎖的原因在於,兩個死鎖位置的代碼均鎖定了共享資源,即阻塞了當前的context
。從線程id也可以看出,死鎖的時候,GetAsync
無法進入GetAsync end 1
那一行,因爲線程1正被阻塞在位置A。導致task的結果沒辦法返回線程1,處於等待中,形成了位置B。
注意,如果string ret = task.Result;
代碼不存在,即不使用task的結果,則兩種情況都不會死鎖。因爲沒有出現搶佔共享資源的情況。
https://www.cnblogs.com/OpenCoder/p/4434574.html 死鎖
https://blog.stephencleary.com/2012/02/async-and-await.html
https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html