[C#學習筆記] - await/async 異步

概述

await/async 關鍵字組合是C#中異步實現的一種常用方式。

  • async用於修飾方法,表明該方法爲異步方法。但只有async+await的組合才能真正實現異步的執行。若“異步方法”內沒有await,則該方法不是異步方法,仍爲同步模式。
  • 由於await只能用於異步方法中,所以方法必須用async修飾。
  • 異步方法的放回類型必須爲voidTaskTask<TResult>中的一種。
  • 異步方法內必須含有await,用於表示異步等待的位置。雖然不太恰當,但有點類似debug中的斷點。
  • await後只能修飾TaskTask<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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章