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

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

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

      C#異步編程由淺入深(二)Async/Await的作用.

      ??考慮到直接講實現一個類Task庫思維有點跳躍,所以本節主要講解Async/Await的本質作用(解決了什么問題),以及Async/Await的工作原理。實現一個類Task的庫則放在后面講。首先回顧一下上篇博客的場景。

       class Program
          {
      
              public static string GetMessage()
              {
                  return Console.ReadLine();
              }
      
              public static  string TranslateMessage(string msg)
              {
                  return msg;
              }
      
              public static  void DispatherMessage(string msg)
              {
                  switch (msg)
                  {
                      case "MOUSE_MOVE":
                          {
                              OnMOUSE_MOVE(msg);
                              break;
                          }
                      case "MOUSE_DOWN":
                          {
                              OnMouse_DOWN(msg);
                              break;
                          }
                      default:
                          break;
                  }
              }
      
              public static void OnMOUSE_MOVE(string msg)
              {
                  Console.WriteLine("開始繪制鼠標形狀");
              }
      
      
              public static int Http()
              {
                  Thread.Sleep(1000);//模擬網絡IO延時
                  return 1;
              }
              public static void HttpAsync(Action<int> action,Action error)
              {
                  //這里我們用另一個線程來實現異步IO,由于Http方法內部是通過Sleep來模擬網絡IO延時的,這里也只能通過另一個線程來實現異步IO
                  //但記住,多線程是實現異步IO的一個手段而已,它不是必須的,后面會講到如何通過一個線程來實現異步IO。
                  Thread thread = new Thread(() => 
                  {
                      try
                      {
                          int res = Http();
                          action(res);
                      }
                      catch
                      {
                          error();
                      }
            
                  });
      
                  thread.Start();
              }
      
              public static Task<int> HttpAsync()
              {
                  return Task.Run(() => 
                  {
                      return Http();
                  });
              }
      
      
              public static void OnMouse_DOWN(string msg)
              {
                  HttpAsync()
                      .ContinueWith(t => 
                      {
                          if(t.Status == TaskStatus.Faulted)
                          {
      
                          }else if(t.Status == TaskStatus.RanToCompletion)
                          {
                              Console.WriteLine(1);
                              //做一些工作
                          }
                      })
                      .ContinueWith(t => 
                      {
                          if (t.Status == TaskStatus.Faulted)
                          {
      
                          }
                          else if (t.Status == TaskStatus.RanToCompletion)
                          {
                              Console.WriteLine(2);
                              //做一些工作
                          }
                      })
                      .ContinueWith(t => 
                      {
                          if (t.Status == TaskStatus.Faulted)
                          {
      
                          }
                          else if (t.Status == TaskStatus.RanToCompletion)
                          {
                              Console.WriteLine(3);
                              //做一些工作
                          }
                      });
              }
      
              static void Main(string[] args)
              {
                  while (true)
                  {
                      string msg = GetMessage();
                      if (msg == "quit") return;
                      string m = TranslateMessage(msg);
                      DispatherMessage(m);
                  }
              }
          }
      
      

      ??在OnMouse_DOWN這個處理函數中,我們使用Task的ContinueWith函數進行鏈式操作,解決了回調地獄問題,但是總感覺有點那么不爽,我們假想有個關鍵字await它能實現以下作用:首先await必須是Task類型,必須是Task類型的(其實不是必要條件,后面會講到)原因是保證必須有ContinueWith這個函數,如果Task沒有返回值,則把await后面的代碼放到Task中的ContinueWith函數體內,如果有返回值,則把Await后的結果轉化為訪問Task.Result屬性,文字說的可能不明白,看下示例代碼

      //無返回值轉換前
      public async void Example()
      {
          Task t = Task.Run(() =>
          {
              Thread.Sleep(1000);
          });
          await t;
          //做一些工作
      }
      //無返回值轉換后
      public void Example()
      {
          Task t = Task.Run(() =>
          {
              Thread.Sleep(1000);
          });
          t.ContinueWith(task => 
          {
              //做一些工作
          });
      }
      
      //有返回值轉換前
      public async void Example()
      {
          Task<int> t = Task.Run<int>(() =>
          {
              Thread.Sleep(1000);
              return 1;
          });
          int res = await t;
          //使用res做一些工作
      }
      //有返回值轉換后
      public void Example()
      {
          Task<int> t = Task.Run<int>(() =>
          {
              Thread.Sleep(1000);
              return 1;
          });
          t.ContinueWith(task => 
          {
              //使用task.Result做一些工作
          });
      }
      

      ??看起來不錯,但至少有以下問題,如下:

      • 該種轉換方法不能很好的轉換Try/Catch結構
      • 在循環結構中使用await不好轉換
      • 該實現與Task類型緊密聯系

      ??一二點是我自己認為的,但第三點是可以從擴展async/await這點被證明的。但無論怎樣,async/await只是對方法按照一定的規則進行了變換而已,它并沒有什么特別之處,具體來講,就是把Await后面要執行的代碼放到一個類似ContinueWith的函數中,在C#中,它是以狀態機的形式表現的,每個狀態都對應一部分代碼,狀態機有一個MoveNext()方法,MoveNext()根據不同的狀態執行不同的代碼,然后每個狀態部分對應的代碼都會設置下一個狀態字段,然后把自身的MoveNext()方法放到類似ContinueWith()的函數中去執行,整個狀態機由回調函數推動。我們嘗試手動轉換以下async/await方法。

      public static Task WorkAsync()
      {
          return Task.Run(() => 
          {
              Thread.Sleep(1000);
              Console.WriteLine("Done!");
          });
      }
      public static async void Test()
      {
          Console.WriteLine("步驟1");
          await WorkAsync();
          Console.WriteLine("步驟2");
          await WorkAsync();
          Console.WriteLine("步驟3");
      }
      

      ??手動寫一個簡單的狀態機類

      public class TestAsyncStateMachine
          {
              public int _state = 0;
              public void Start() => MoveNext();
              public void MoveNext()
              {
                  switch(_state)
                  {
                      case 0:
                          {
                              goto Step0;
                          }
                      case 1:
                          {
                              goto Step1;
                          }
                      default:
                          {
                              Console.WriteLine("步驟3");
                              return;
                          }
                  }
      
              Step0:
                  {
                      Console.WriteLine("步驟1");
                      _state = 1;
                      WorkAsync().ContinueWith(t => this.MoveNext());
                      return;
                  }
              Step1:
                  {
                      _state = -1;
                      Console.WriteLine("步驟2");
                      WorkAsync().ContinueWith(t => this.MoveNext());
                      return;
                  }
      
              }
          }
      

      ??而Test()方法則變成了這樣

      public static void Test()
      {
          new TestAsyncStateMachine().Start();
      }
      

      ??注意Test()方法返回的是void,這意味這調用方將不能await Test()。如果返回Task,這個狀態機類是不能正確處理的,如果要正確處理,那么狀態機在Start()啟動后,必須返回一個Task,而這個Task在整個狀態機流轉完畢后要變成完成狀態,以便調用方在該Task上調用的ContinueWith得以繼續執行,而就Task這個類而言,它是沒有提供這種方法(內部有,但沒有對外暴露)來主動控制Task的狀態的,這個與JS中的Promise不同,JS里面用Reslove函數來主動控制Promise的狀態,并導致在該Promise上面的Then鏈式調用得以繼續完成,而在C#里面怎么做呢?既然使用了狀態機來實現async/await,那么在轉換一個返回Task的函數時肯定會遇到,怎么處理?后面講。
      ??首先解決一下與Task類型緊密聯系這個問題。
      ??從狀態機中可以看到,主要使用到了Task中的ContinueWith這個函數,它的語義是在任務完成后,執行回調函數,通過回調函數拿到結果,這個編程風格也叫做CPS(Continuation-Passing-Style, 續體傳遞風格),那么我們能不能把這個函數給抽象出來呢?語言開發者當然想到了,它被抽象成了一個Awaiter因此編譯器要求await的類型必須要有GetAwaiter方法,什么樣的類型才是Awaiter呢?編譯器規定主要實現了如下幾個方法的類型就是Awaiter:

      • 必須繼承INotifyCompletion接口,并實現其中的OnCompleted(Action continuation)方法
      • 必須包含IsCompleted屬性
      • 必須包含GetResult()方法

      ??第一點好理解,第二點的作用是熱路徑優化,第三點以后講。我們再改造一下我們手動寫的狀態機。

      public class TestAsyncStateMachine
      {
          public int _state = 0;
          public void Start() => MoveNext();
          public void MoveNext()
          {
              switch(_state)
              {
                  case 0:
                      {
                          goto Step0;
                      }
                  case 1:
                      {
                          goto Step1;
                      }
                  default:
                      {
                          Console.WriteLine("步驟3");
                          return;
                      }
              }
      
          Step0:
              {
                  Console.WriteLine("步驟1");
                  _state = 1;
                  TaskAwaiter taskAwaiter;
                  taskAwaiter = WorkAsync().GetAwaiter();
                  if (taskAwaiter.IsCompleted) goto Step1;
                  taskAwaiter.OnCompleted(() => this.MoveNext());
                  return;
              }
          Step1:
              {
                  _state = -1;
                  Console.WriteLine("步驟2");
                  TaskAwaiter taskAwaiter;
                  taskAwaiter = WorkAsync().GetAwaiter();
                  if (taskAwaiter.IsCompleted) MoveNext();
                  taskAwaiter.OnCompleted(() => this.MoveNext());
                  return;
              }
      
          }
      }
      

      ??可以看到去掉了與Task中ContinueWith的耦合關系,并且如果任務已經完成,則可以直接執行下個任務,避免了無用的開銷。
      ??因此我們可以總結一下async/await:

      • async/await只是表示這個方法需要編譯器進行特殊處理,并不代表它本身一定是異步的。
      • Task類中的GetAwaiter主要是給編譯器用的。

      ??第一點我們可以用以下例子來證明,有興趣的朋友可以自己去驗證以下,以便加深理解。

      //該類型包含GetAwaiter方法,且GetAwaiter()返回的類型包含三個必要條件
      public class MyAwaiter : INotifyCompletion
      {
          public void OnCompleted(Action continuation)
          {
              continuation();
          }
      
          public bool IsCompleted { get; }
          public void GetResult()
          {
          
          }
      
          public MyAwaiter GetAwaiter() => new MyAwaiter();
      }
      

      ??一個測試函數,注意必須返回void

      public static async void AwaiterTest()
      {
          await new MyAwaiter();
          Console.WriteLine("Done");
      }
      

      ??可以看到這是完全同步進行的。
      ??覺得有收獲的不妨點個贊,有支持才有動力寫出更好的文章。

      posted @ 2021-04-10 19:11  白煙染黑墨  閱讀(3973)  評論(6)    收藏  舉報
      主站蜘蛛池模板: 国产亚洲精品在av| 中国亚州女人69内射少妇| 无码人妻精品一区二区三区下载| 日本夜爽爽一区二区三区| 激情综合网五月婷婷| 性动态图无遮挡试看30秒| 久久久久无码精品国产AV| 高清中文字幕一区二区| 亚洲av不卡电影在线网址最新| 99久久免费只有精品国产| 国产偷窥熟女高潮精品视频| 色欲天天婬色婬香综合网| 亚洲VA欧美VA国产综合| 久久亚洲精品情侣| 国产一区二区三区在线看| 国产成人精品免费视频app软件 | 亚洲欧洲一区二区精品| 精品国产AV无码一区二区三区| 亚洲精品国产美女久久久| 日韩一区二区黄色一级片| 国产老女人免费观看黄A∨片 | 国产怡春院无码一区二区| 18禁动漫一区二区三区| 九九热视频在线免费观看| 太仓市| 蜜臀av日韩精品一区二区| 国产99视频精品免费视频36| 久久国产成人av蜜臀| 免费超爽大片黄| 国产伦码精品一区二区| 青青青爽在线视频观看| 漂亮的保姆hd完整版免费韩国| 久久亚洲色WWW成人男男| 国产成人午夜福利在线播放| 国产盗摄视频一区二区三区| 日日躁狠狠躁狠狠爱| 亚洲综合成人av在线| 久热这里有精品视频播放| 2021国产在线视频| 色综合热无码热国产| 欧美极品色午夜在线视频|