ConfigureAwait


默認情況下,當您使用async/await時,它將在開始請求的原始線程上繼續運行(狀態機)。

但是,如果當前另一個長時間運行的進程已經接管了該線程,那么你就不得不等待它完成。要避免這個問題,可以使用ConfigureAwait的方法和false參數。當你用這個方法的時候,這將告訴Task它可以在任何可用的線程上恢復自己繼續運行,而不是等待最初創建它的線程。這將加快響應速度並避免許多死鎖。

但是,這里有一點點損失。當您在另一個線程上繼續時,線程同步上下文將丟失,因為狀態機改變。這里最大的損失是你會失去歸屬於線程的Culture和Language,其中包含了國家語言時區信息,以及來自原始線程的HttpContext.Current之類的信息,因此,如果您不需要以此來做多語系或操作任何HttpContext類型設置,則可以安全地進行此方法的調用。注意:如果需要language/culture,可以始終在await之前存儲當前相關狀態值,然后在await新線程之后重新應用它。

注意事項

如果有同步方法調用異步方法,則必須使用ConfigureAwait(false)。如果不這樣做,就會立即掉進死鎖陷阱。

發生的情況是主線程將調用async方法,最終會阻塞這個線程,直到那個async方法完成。然而,一旦異步方法完成,它必須等待原始調用者完成后才能繼續。他們都在等待對方完成,而且永遠不會。通過在調用中使用configurewait (false), async方法將能夠在另一個線程上完成自己操作,而不關心自己的狀態機的位置,並通知原始線程它已經完成。

死鎖舉例

 public class HomeController : Controller
    {
        public  ActionResult Index()
        {
             DoAsync().Wait();//同步調用1,發生死鎖
             //var r = DoAsync().Result;//同步調用2,發生死鎖
             return View();
        }
 
        public async Task<int> DoAsync()
        {
            await Task.Delay(2000).ConfigureAwait(true);//默認就是ture
            return 1;
        }
    }
View Code

探討.NetCore中異步注意事項

在.NetCore中已經剔除了SynchronizationContext,剔除他的主要原因主要是性能和進一步簡化操作

在.NetCore中我們不用繼續關心異步同步混用情況下,是否哪里沒有設置ConfigureAwait(false) 會導致的死鎖問題,因為在.netcore中的async/await 可能在任何線程上執行,並且可能並行運行!

如下代碼,在舊版ASP.NET(.NetFramework)中工作正常,而ASP.NET Core上不是線程安全的

public class HomeController : Controller
    {
        public async Task<ActionResult> Index()
        {            
            var result = await GetBothAsync();
            return View();
        }
        async Task<List<string>> GetBothAsync()
        {
            var result = new List<string>();
            var task1 = GetOneAsync(result);
            var task2 = GetOneAsync(result);
            await Task.WhenAll(task1, task2);
            return result;
        }
        async Task GetOneAsync(List<string> result)
        {
            await Task.Delay(2000);
            for (int i = 0; i < 10 * 10 * 10 * 10 * 10; i++)
            {
                result.Add(i.ToString());
            }
        }
}
View Code

此代碼在舊版ASP.NET(.NetFramework)中工作正常,由於請求處設置了await,請求上下文一次只允許一個連接.

其中result.Add(data)一次只能由一個線程執行,因為它在請求上下文中執行。(可以理解為在源線程執行,是吧?QAQ)

但是,這個相同的代碼在ASP.NET Core上是不安全的; 具體地說,該result.Add(data)行可以由兩個線程同時執行,而不保護共享List<string>

所以在.Netcore中要特別注意異步代碼在並行執行情況下引發的問題

 

源博客地址1


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM