乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      探索c#之Async、Await剖析

       深秋微涼3 2016-02-07

      (點(diǎn)擊上方藍(lán)字,可快速關(guān)注我們)


      來(lái)自:蘑菇先生

      鏈接:http://www.cnblogs.com/mushroom/p/4575417.html


      基本介紹


      Async、Await是net4.x新增的異步編程方式,其目的是為了簡(jiǎn)化異步程序編寫,和之前APM方式簡(jiǎn)單對(duì)比如下。


      APM方式,BeginGetRequestStream需要傳入回調(diào)函數(shù),線程碰到BeginXXX時(shí)會(huì)以非阻塞形式繼續(xù)執(zhí)行下面邏輯,完成后回調(diào)先前傳入的函數(shù)。


      HttpWebRequest myReq =(HttpWebRequest)WebRequest.Create('http://cnblogs.com/');

      myReq.BeginGetRequestStream();

      //to do


      Async方式,使用Async標(biāo)記Async1為異步方法,用Await標(biāo)記GetRequestStreamAsync表示方法內(nèi)需要耗時(shí)的操作。主線程碰到await時(shí)會(huì)立即返回,繼續(xù)以非阻塞形式執(zhí)行主線程下面的邏輯。當(dāng)await耗時(shí)操作完成時(shí),繼續(xù)執(zhí)行Async1下面的邏輯


      static async void Async1()

      {

      HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create('http://cnblogs.com/');

      await myReq.GetRequestStreamAsync();

      //to do

      }


      上面是net類庫(kù)實(shí)現(xiàn)的異步,如果要實(shí)現(xiàn)自己方法異步。


      APM方式:


      public delegate int MyDelegate(int x);

      MyDelegate mathDel = new MyDelegate((a) => { return 1; });

      mathDel.BeginInvoke(1, (a) => { },null);


      Async方式:



      static async void Async2()

      {

      await Task.Run(() => { Thread.Sleep(500); Console.WriteLine('bbb'); });

      Console.WriteLine('ccc');

      }

      Async2();

      Console.WriteLine('aaa');


      對(duì)比下來(lái)發(fā)現(xiàn),async/await是非常簡(jiǎn)潔優(yōu)美的,需要寫的代碼量更少,更符合人們編寫習(xí)慣。


      因?yàn)槿说乃季S對(duì)線性步驟比較好理解的。


      APM異步回調(diào)的執(zhí)行步驟是:A邏輯->假C回調(diào)邏輯->B邏輯->真C回調(diào)邏輯,這會(huì)在一定程度造成思維的混亂,當(dāng)一個(gè)項(xiàng)目中出現(xiàn)大量的異步回調(diào)時(shí),就會(huì)變的難以維護(hù)。


      Async、Await的加入讓原先這種混亂的步驟,重新?lián)苷?,?zhí)行步驟是:A邏輯->B邏輯->C邏輯。


      基本原理剖析


      作為一個(gè)程序員的自我修養(yǎng),刨根問底的好奇心是非常重要的。 Async剛出來(lái)時(shí)會(huì)讓人有一頭霧水的感覺,await怎么就直接返回了,微軟怎么又出一套新的異步模型。那是因?yàn)榱?xí)慣了之前的APM非線性方式導(dǎo)致的,現(xiàn)在重歸線性步驟反而不好理解。 學(xué)習(xí)Async時(shí)候,可以利用已有的APM方式去理解,以下代碼純屬虛構(gòu)。


      比如把Async2方法想象APM方式的Async3方法:


      static async void Async3()

      {

      var task= await Task.Run(() => { Thread.Sleep(500); Console.WriteLine('bbb'); });

      //注冊(cè)task完成后回調(diào)

      task.RegisterCompletedCallBack(() =>

      {

      Console.WriteLine('ccc');

      });

      }


      上面看其來(lái)就比較好理解些的,再把Async3方法想象Async4方法:


      static void Async4()

      {

      var thread = new Thread(() =>

      {

      Thread.Sleep(500);

      Console.WriteLine('bbb');

      });

      //注冊(cè)thread完成后回調(diào)

      thread.RegisterCompletedCallBack(() =>

      {

      Console.WriteLine('ccc');

      });

      thread.Start();

      }


      這樣看起來(lái)就非常簡(jiǎn)單明了,連async都去掉了,變成之前熟悉的編程習(xí)慣。雖然代碼純屬虛構(gòu),但基本思想是相通的,差別在于實(shí)現(xiàn)細(xì)節(jié)上面。


      內(nèi)部實(shí)現(xiàn)剖析


      作為一個(gè)程序員的自我修養(yǎng),嚴(yán)謹(jǐn)更是不可少的態(tài)度。上面的基本思想雖然好理解了,但具體細(xì)節(jié)呢,編程是個(gè)來(lái)不得半點(diǎn)虛假的工作,那虛構(gòu)的代碼完全對(duì)不住看官們啊。


      繼續(xù)看Async2方法,反編譯后的完整代碼如下:


      internal class Program

      {

      // Methods

      [AsyncStateMachine(typeof(d__2)), DebuggerStepThrough]

      private static void Async2()

      {

      d__2 d__;

      d__.<>t__builder = AsyncVoidMethodBuilder.Create();

      d__.<>1__state = -1;

      d__.<>t__builder.Startd__2>(ref d__);

      }


      private static void Main(string[] args)

      {

      Async2();

      Console.WriteLine('aaa');

      Console.ReadLine();

      }


      // Nested Types

      [CompilerGenerated]

      private struct d__2 : IAsyncStateMachine

      {

      // Fields

      public int <>1__state;

      public AsyncVoidMethodBuilder <>t__builder;

      private object <>t__stack;

      private TaskAwaiter <>u__$awaiter3;


      // Methods

      private void MoveNext()

      {

      try

      {

      TaskAwaiter awaiter;

      bool flag = true;

      switch (this.<>1__state)

      {

      case -3:

      goto Label_00C5;


      case 0:

      break;


      default:

      if (Program.CS$<>9__CachedAnonymousMethodDelegate1 == null)

      {

      Program.CS$<>9__CachedAnonymousMethodDelegate1 = new Action(Program.b__0);

      }

      awaiter = Task.Run(Program.CS$<>9__CachedAnonymousMethodDelegate1).GetAwaiter();

      if (awaiter.IsCompleted)

      {

      goto Label_0090;

      }

      this.<>1__state = 0;

      this.<>u__$awaiter3 = awaiter;

      this.<>t__builder.AwaitUnsafeOnCompletedd__2>(ref awaiter, ref this);

      flag = false;

      return;

      }

      awaiter = this.<>u__$awaiter3;

      this.<>u__$awaiter3 = new TaskAwaiter();

      this.<>1__state = -1;

      Label_0090:

      awaiter.GetResult();

      awaiter = new TaskAwaiter();

      Console.WriteLine('ccc');

      }

      catch (Exception exception)

      {

      this.<>1__state = -2;

      this.<>t__builder.SetException(exception);

      return;

      }

      Label_00C5:

      this.<>1__state = -2;

      this.<>t__builder.SetResult();

      }


      [DebuggerHidden]

      private void SetStateMachine(IAsyncStateMachine param0)

      {

      this.<>t__builder.SetStateMachine(param0);

      }

      }


      public delegate int MyDelegate(int x);

      }


      Collapse Methods

      發(fā)現(xiàn)async、await不見了,原來(lái)又是編譯器級(jí)別提供的語(yǔ)法糖優(yōu)化,所以說(shuō)async不算是全新的異步模型。 可以理解為async更多的是線性執(zhí)行步驟的一種回歸,專門用來(lái)簡(jiǎn)化異步代碼編寫。


      從反編譯后的代碼看出編譯器新生成一個(gè)繼承IAsyncStateMachine 的狀態(tài)機(jī)結(jié)構(gòu)asyncd(代碼中叫d__2,后面簡(jiǎn)寫AsyncD),下面是基于反編譯后的代碼來(lái)分析的。


      IAsyncStateMachine最基本的狀態(tài)機(jī)接口定義:


      public interface IAsyncStateMachine

      {

      void MoveNext();

      void SetStateMachine(IAsyncStateMachine stateMachine);

      }


      既然沒有了async、await語(yǔ)法糖的阻礙,就可以把代碼執(zhí)行流程按線性順序來(lái)理解,其整個(gè)執(zhí)行步驟如下:


      1. 主線程調(diào)用Async2()方法

      2. Async2()方法內(nèi)初始化狀態(tài)機(jī)狀態(tài)為-1,啟動(dòng)AsyncD

      3. MoveNext方法內(nèi)部開始執(zhí)行,其task.run函數(shù)是把任務(wù)扔到線程池里,返回個(gè)可等待的任務(wù)句柄。MoveNext源碼剖析:


      //要執(zhí)行任務(wù)的委托


      Program.CS$<>9__CachedAnonymousMethodDelegate1 = new Action(Program.b__0);


      //開始使用task做異步,是net4.0基于任務(wù)task的編程方式。


      awaiter =Task.Run(Program.CS$<>9__CachedAnonymousMethodDelegate1).GetAwaiter();


      //設(shè)置狀態(tài)為0,以便再次MoveNext直接break,執(zhí)行switch后面的邏輯,典型的狀態(tài)機(jī)模式。


      this.<>1__state = 0;


      //返回調(diào)用async2方法的線程,讓其繼續(xù)執(zhí)行主線程后面的邏輯


      this.<>t__builder.AwaitUnsafeOnCompletedd__2>(ref awaiter, ref this);

      return;


      4. 這時(shí)就已經(jīng)有2個(gè)線程在跑了,分別是主線程和Task.Run在跑的任務(wù)線程。


      5. 執(zhí)行主線程后面邏輯輸出aaa,任務(wù)線程運(yùn)行完成后輸出bbb、在繼續(xù)執(zhí)行任務(wù)線程后面的業(yè)務(wù)邏輯輸出ccc。


      Label_0090:

      awaiter.GetResult();

      awaiter = new TaskAwaiter();

      Console.WriteLine('ccc');


      這里可以理解為async把整個(gè)主線程同步邏輯,分拆成二塊。 第一塊是在主線程直接執(zhí)行,第二塊是在任務(wù)線程完成后執(zhí)行, 二塊中間是任務(wù)線程在跑,其源碼中awaiter.GetResult()就是在等待任務(wù)線程完成后去執(zhí)行第二塊。


      從使用者角度來(lái)看執(zhí)行步驟即為: 主線程A邏輯->異步任務(wù)線程B邏輯->主線程C邏輯。


      Test();

      Console.WriteLine('A邏輯');

      static async void Test()

      {

      await Task.Run(() => { Thread.Sleep(1000); Console.WriteLine('B邏輯'); });

      Console.WriteLine('C邏輯');

      }


      回過頭來(lái)對(duì)比下基本原理剖析小節(jié)中的虛構(gòu)方法Async4(),發(fā)現(xiàn)區(qū)別在于一個(gè)是完成后回調(diào),一個(gè)是等待完成后再執(zhí)行,這也是實(shí)現(xiàn)異步最基本的兩大類方式。


      重點(diǎn)注意的地方


      主線程A邏輯->異步任務(wù)線程B邏輯->主線程C邏輯。


      注意:這3個(gè)步驟是有可能會(huì)使用同一個(gè)線程的,也可能會(huì)使用2個(gè),甚至3個(gè)線程。 可以用Thread.CurrentThread.ManagedThreadId測(cè)試下得知。


      Async7();

      Console.WriteLine(Thread.CurrentThread.ManagedThreadId);

      static async void Async7()

      {

      await Task.Run(() =>

      {

      Console.WriteLine(Thread.CurrentThread.ManagedThreadId);

      });

      Console.WriteLine(Thread.CurrentThread.ManagedThreadId);

      }


      正由于此,才會(huì)有言論說(shuō)Async不用開線程,也有說(shuō)需要開線程的,從單一方面來(lái)講都是對(duì)的,也都是錯(cuò)的。 上面源碼是從簡(jiǎn)分析的,具體async內(nèi)部會(huì)涉及到線程上下文切換,線程復(fù)用、調(diào)度等。 想深入的同學(xué)可以研究下ExecutionContextSwitcher、 SecurityContext.RestoreCurrentWI、ExecutionContext這幾個(gè)東東。


      其實(shí)具體的物理線程細(xì)節(jié)可以不用太關(guān)心,知道其【主線程A邏輯->異步任務(wù)線程B邏輯->主線程C邏輯】這個(gè)基本原理即可。 另外Async也會(huì)有線程開銷的,所以要合理分業(yè)務(wù)場(chǎng)景去使用。


      總結(jié)


      從逐漸剖析Async中發(fā)現(xiàn),Net提供的異步方式基本上一脈相承的,如:


      1. net4.5的Async,拋去語(yǔ)法糖就是Net4.0的Task+狀態(tài)機(jī)。

      2. net4.0的Task, 退化到3.5即是(Thread、ThreadPool)+實(shí)現(xiàn)的等待、取消等API操作。


      本文以async為起點(diǎn),簡(jiǎn)單剖析了其內(nèi)部原理及實(shí)現(xiàn),希望對(duì)大家有所幫助。



      DotNet

      微信號(hào):iDotNet

      打造東半球最好的 .Net 微信號(hào)

      --------------------------------------

      商務(wù)合作QQ:2302462408

      投稿網(wǎng)址:top.jobbole.com

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多