<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      小心C# 5.0 中的await and async模式造成的死鎖

      小心C# 5.0 中的await and async模式造成的死鎖

       

      平時在使用C# 5.0中的await and async關鍵字的時候總是沒注意,直到今天在調試一個ASP.NET項目時,發現在調用一個聲明為async的方法后,程序老是莫名其妙的被卡住,就算聲明為async的方法中的Task任務執行完畢后,外部方法的await調用還是阻塞著,后來查到了下面這篇文章,才恍然大悟原來await and async模式使用不當很容易造成程序死鎖,下面這篇文章通過一個Winform示例和一個Asp.net示例介紹了await and async模式是如何造成程序死鎖的,以及如何避免這種死鎖。

      原文鏈接

       

      UI Example

      Consider the example below. A button click will initiate a REST call and display the results in a text box (this sample is for Windows Forms, but the same principles apply to any UI application).

      復制代碼
      // My "library" method.
      public static async Task<JObject> GetJsonAsync(Uri uri)
      {
        using (var client = new HttpClient())
        {
          var jsonString = await client.GetStringAsync(uri);
          return JObject.Parse(jsonString);
        }
      }
      
      // My "top-level" method.
      public void Button1_Click(...)
      {
        var jsonTask = GetJsonAsync(...);
        textBox1.Text = jsonTask.Result;
      }
      復制代碼

      The “GetJson” helper method takes care of making the actual REST call and parsing it as JSON. The button click handler waits for the helper method to complete and then displays its results.

      This code will deadlock.

       

       

      ASP.NET Example

      This example is very similar; we have a library method that performs a REST call, only this time it’s used in an ASP.NET context (Web API in this case, but the same principles apply to any ASP.NET application):

      復制代碼
      // My "library" method.
      public static async Task<JObject> GetJsonAsync(Uri uri)
      {
        using (var client = new HttpClient())
        {
          var jsonString = await client.GetStringAsync(uri);
          return JObject.Parse(jsonString);
        }
      }
      
      // My "top-level" method.
      public class MyController : ApiController
      {
        public string Get()
        {
          var jsonTask = GetJsonAsync(...);
          return jsonTask.Result.ToString();
        }
      }
      復制代碼

      This code will also deadlock. For the same reason.

       

       

       

      What Causes the Deadlock

      Here’s the situation: remember from my intro post that after you await a Task, when the method continues it will continue in a context.

      In the first case, this context is a UI context (which applies to any UI except Console applications). In the second case, this context is an ASP.NET request context.

      One other important point: an ASP.NET request context is not tied to a specific thread (like the UI context is), but it does only allow one thread in at a time. This interesting aspect is not officially documented anywhere AFAIK, but it is mentioned in my MSDN article about SynchronizationContext.

      So this is what happens, starting with the top-level method (Button1_Click for UI / MyController.Get for ASP.NET):

      1. The top-level method calls GetJsonAsync (within the UI/ASP.NET context).
      2. GetJsonAsync starts the REST request by calling HttpClient.GetStringAsync (still within the context,這里的within the context表示的是GetJsonAsync方法依然用的是執行top-level method的線程來執行,也就是主線程).
      3. GetStringAsync returns an uncompleted Task, indicating the REST request is not complete.
      4. GetJsonAsync awaits the Task returned by GetStringAsync. The context(這里的context依然指的是執行top-level method的線程,當GetStringAsync方法執行完畢返回后,GetJsonAsync會繼續用執行top-level method的線程來執行await關鍵字之后的代碼,這也是造成本例中代碼會死鎖的原因) is captured and will be used to continue running the GetJsonAsync method later. GetJsonAsync returns an uncompleted Task, indicating that the GetJsonAsync method is not complete.
      5. The top-level method synchronously blocks on the Task returned by GetJsonAsync. This blocks the context thread.
      6. … Eventually, the REST request will complete. This completes the Task that was returned by GetStringAsync.
      7. The continuation for GetJsonAsync is now ready to run, and it waits for the context to be available so it can execute in the context.
      8. Deadlock. The top-level method is blocking the context thread, waiting for GetJsonAsync to complete, and GetJsonAsync is waiting for the context to be free so it can complete.

      For the UI example, the “context” is the UI context; for the ASP.NET example, the “context” is the ASP.NET request context. This type of deadlock can be caused for either “context”.

      上面內容的大致意思就是說在使用await and async模式時,await關鍵字這一行后面的代碼塊會被一個context(也就是上面提到的ASP.NET request context和UI context)線程繼續執行,如果我們將本例中調用top-level method的線程稱為線程A(即context線程),由于GetJsonAsync方法也是由線程A調用的,所以當GetJsonAsync方法中await的GetStringAsync方法執行完畢后,GetJsonAsync需要重新使用線程A執行await代碼行之后的代碼,而現在由于線程A在top-level method的代碼中因為訪問了jsonTask.Result被阻塞了(因為線程A調用top-level method代碼中jsonTask.Result的時候,await的GetStringAsync的Task還沒執行完畢,所以線程A被阻塞),所以GetJsonAsync無法重新使用線程A執行await代碼行之后的代碼塊,也被阻塞,所以形成了死鎖。也就是說top-level method代碼中線程A因為等待GetJsonAsync中await的GetStringAsync結束被阻塞,而GetStringAsync也等待線程A在top-level method的阻塞結束獲得線程A來執行GetJsonAsync中await代碼行后面的代碼也被阻塞,兩個阻塞相互等待,相互死鎖。

      Preventing the Deadlock

      There are three best practices (both covered in my intro post) that avoid this situation:

      1. In your “library” async methods, use ConfigureAwait(false) wherever possible.
      2. Don’t block on Tasks; use async all the way down.
      3. 如果想結束async & await模式的調用,啟動一個新的線程去await異步方法的返回結果

      這里我補充一下,如果你開發的是Winform程序,那么最好用第二種方法避免死鎖,也就是不要阻塞主線程,這樣當await等待的Task對象線程執行完畢后,由于主線程沒有被阻塞,因此await后面的代碼就會在恰當的時候(這里提到的“恰當的時候”是由.Net Framework自己判斷的,.Net Framework會安排主線程在某個時候繼續執行await后面的代碼)繼續在主線程上執行完畢。之所以在Winform中不推薦用第一種方法是因為第一種方法會讓await后面的代碼在另外的線程上執行,而不再是在主線程上執行,如果await后有代碼設置了Winform控件的值,那么會引起Winform程序的線程安全問題,所以在Winform中最好的辦法還是不要阻塞主線程,讓await后面的代碼能夠在主線程上執行。但在Asp.net中用上面第一種或第二種方法都可以,不存在線程安全問題。

      Consider the first best practice. The new “library” method looks like this:

      復制代碼
      public static async Task<JObject> GetJsonAsync(Uri uri)
      {
        using (var client = new HttpClient())
        {
          var jsonString = await client.GetStringAsync(uri).ConfigureAwait(false);
          return JObject.Parse(jsonString);
        }
      }
      復制代碼

      This changes the continuation behavior of GetJsonAsync so that it does not resume on the context. Instead, GetJsonAsync will resume on a thread pool thread. This enables GetJsonAsync to complete the Task it returned without having to re-enter the context.

      Consider the second best practice. The new “top-level” methods look like this:

      復制代碼
      public async void Button1_Click(...)
      {
        var json = await GetJsonAsync(...);
        textBox1.Text = json;
      }
      
      public class MyController : ApiController
      {
        public async Task<string> Get()
        {
          var json = await GetJsonAsync(...);
          return json.ToString();
        }
      }
      復制代碼

      This changes the blocking behavior of the top-level methods so that the context is never actually blocked; all “waits” are “asynchronous waits”.

      Note: It is best to apply both best practices. Either one will prevent the deadlock, but both must be applied to achieve maximum performance and responsiveness.

      The third best practice:如果想結束async & await模式的調用,啟動一個新的線程去await異步方法的返回結果:

      復制代碼
      // My "library" method.
      public static async Task<JObject> GetJsonAsync(Uri uri)
      {
          using (var client = new HttpClient())
          {
              var jsonString = await client.GetStringAsync(uri);
              return JObject.Parse(jsonString);
          }
      }
      
      // My "top-level" method.
      public string Get()
      {
          string jsonResultString = string.Empty;
      
          Task.Run(async () =>
          {
              jsonResultString = await GetJsonAsync(...);
           //await之后的代碼
          }).Wait();//此處啟動線程是為了防止Async & Await模式造成死鎖
      
          return jsonResultString;
      }
      復制代碼

      這樣因為GetJsonAsync方法是由Task.Run新啟動的線程來調用的,所以在await GetJsonAsync(...)執行完畢之后,.Net Framework就會用Task.Run新啟動的線程來執行await之后的代碼(而Task.Run啟動的新線程執行到await GetJsonAsync(...)后就進入閑置狀態了,所以一旦await的GetJsonAsync方法真正執行完畢后,由于Task.Run啟動的新線程現在沒有被阻塞,所以就可以立即被用來執行await之后的代碼),不會和top-level method的線程(即context線程)相互阻塞,造成死鎖。

       

      最后再補充說一點,本文提到的await and async死鎖問題,在.Net控制臺程序中并不存在。因為經過實驗發現在.Net控制臺程序中,await關鍵字這一行后面的代碼默認就是在一個新的線程上執行的,也就是說在控制臺程序中就算不調用Task.ConfigureAwait(false),await關鍵字這一行后面的代碼也會在一個新啟動的線程上執行,不會和主線程發生死鎖。但是在Winform和Asp.net中就會發生死鎖。

       

       

      http://www.rzrgm.cn/OpenCoder/p/4434574.html

       

      參考文檔:http://www.rzrgm.cn/heyuquan/p/async-deadlock.html

      posted @ 2019-07-10 15:44  Shikyoh  閱讀(392)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲国产精品久久久久秋霞影院 | 丁香花在线观看免费观看图片 | 2021国产成人精品久久| 九九热在线视频观看精品| 人妻少妇偷人精品一区| 国产一区二区在线有码| 日韩人妻一区中文字幕| 精品黄色av一区二区三区| 久久精品中文字幕少妇| 国产成人av三级在线观看| 亚洲一区在线成人av| 天堂√最新版中文在线地址| 婷婷色综合成人成人网小说| 日韩美少妇大胆一区二区| 国产精品店无码一区二区三区| av中文字幕国产精品| 男人扒开添女人下部免费视频| 亚洲国产成人字幕久久| 亚洲国产成熟视频在线多多| 国产精品一区二区色综合| 亚洲成av人片无码迅雷下载| 人妻一区二区三区三区| 亚洲中文无码永久免费| 美女内射无套日韩免费播放| 福利一区二区1000| 亚洲一区二区av高清| 55大东北熟女啪啪嗷嗷叫| 国产95在线 | 欧美| 起碰免费公开97在线视频| 最新国产AV最新国产在钱| 霍邱县| 丰满妇女强制高潮18xxxx| 性无码专区无码| 欧美激情一区二区三区成人 | 国产精品一区二区小视频| 美日韩精品一区二区三区| 蜜臀av午夜精品福利| 国产福利片无码区在线观看| 国产精品三级国产精品高| 国产成人无码一区二区三区在线 | 国产成人无码免费视频麻豆|