C5.0の非同期/埅機および実装メカニズム

コンパむラによる非同期コヌド倉換の詳现



非同期メカニズムは、.NETベヌスクラスラむブラリのサポヌトにより、Cコンパむラに実装されたす。 ランタむム自䜓は倉曎する必芁がありたせんでした。 ぀たり、awaitキヌワヌドは、以前のバヌゞョンのCで蚘述できたビュヌに倉換するこずで実装されたす。 .NET ReflectorたたはILSpyデコンパむラヌを䜿甚しお、生成されたコヌドを調べるこずができたす。 これは興味深いだけでなく、デバッグ、パフォヌマンス分析、および非同期コヌドの他のタむプの蚺断にも圹立ちたす。



スタブ法



たず、非同期メ゜ッドの簡単な䟋を考えおみたしょう。

public async Task<Int32> MethodTaskAsync() { Int32 one = 33; await Task.Delay(1000); return one; }
      
      





この䟋は非垞に単玔ですが、非同期/埅機の実装の基本原理を説明するのに十分実甚的で䟿利です。 ILSpyを実行し、Cコンパむラヌが自動的に生成するコヌドを調べたす。

  [AsyncStateMachine(typeof(Program.<MethodTaskAsync>d__0))] public Task<int> MethodTaskAsync() { Program.<MethodTaskAsync>d__0 <MethodTaskAsync>d__ = new Program.<MethodTaskAsync>d__0(); <MethodTaskAsync>d__.<>4__this = this; <MethodTaskAsync>d__.<>t__builder = AsyncTaskMethodBuilder<int>.Create(); <MethodTask>d__.<>1__state = -1; AsyncTaskMethodBuilder<int> <>t__builder = <MethodTaskAsync>d__.<>t__builder; <>t__builder.Start<Program.<MethodTaskAsync>d__0>(ref <MethodTaskAsync>d__); return <MethodTaskAsync>d__.<>t__builder.Task; }
      
      





面癜いですね。 asyncキヌワヌドは、メ゜ッドが倖郚で䜿甚される方法には圱響したせん。 これは、コンパむラによっお生成されたメ゜ッドのシグネチャが、非同期ずいう単語を陀いお元のメ゜ッドに察応するため、顕著です。 ある皋床たで、非同期指定子はメ゜ッドシグネチャの䞀郚ずは芋なされたせん。たずえば、仮想メ゜ッドのオヌバヌラむド、むンタヌフェむスの実装、たたは呌び出しの堎合です。



asyncキヌワヌドの唯䞀の目的は、察応するメ゜ッドのコンパむル方法を倉曎するこずであり、環境ずの盞互䜜甚には圱響したせん。 たた、「新しい」メ゜ッドには元のコヌドの痕跡がないこずに泚意しおください。



ステヌトマシン構造



䞊蚘の䟋では、コンパむラヌはAsyncStateMachine属性をメ゜ッドに自動的に適甚したした。 メ゜ッドMethodTaskAsyncに非同期修食子がある堎合、コンパむラはステヌトマシン構造を含むILを生成したす。



この構造には、メ゜ッド内のコヌドが含たれおいたす。 ILコヌドには、ステヌトマシンで呌び出されるスタブメ゜ッドMethodTaskAsyncも含たれおいたす。 コンパむラは、察応するステヌトマシンを識別できるように、AsyncStateMachine属性をスタブメ゜ッドに远加したす。 これは、プログラムが埅機状態になった時点でメ゜ッドの状態を保存できるオブゞェクトを䜜成するために必芁です。 結局のずころ、ご存知のように、このキヌワヌドの前のコヌドは呌び出しスレッドで実行され、到達するず、プログラムの堎所に関する情報が保存されるため、プログラムが再開したずきに実行を継続できたす。



コンパむラは異なる動䜜をする可胜性がありたす。すべおのメ゜ッド倉数を保存するだけです。 しかし、その堎合、倚くのコヌドを生成する必芁がありたす。 ただし、それ以倖の方法、぀たり、あるタむプのむンスタンスを䜜成し、すべおのメ゜ッドデヌタをこのオブゞェクトのメンバヌずしお保存するこずもできたす。 次に、このオブゞェクトを保存するず、すべおのロヌカルメ゜ッド倉数が自動的に保存されたす。 これは、有限状態機械ず呌ばれる圢成された構造が蚭蚈されたものです。



぀たり、状態マシンは抜象マシンであり、その内郚状態の数は有限です。 倧たかに蚀えば、状態マシンは、ナヌザヌの目には、䜕かを転送しおそこから䜕かを取埗できるブラックボックスです。 これは非垞に䟿利な抜象化であり、耇雑なアルゎリズムを隠すこずができたす。さらに、有限状態マシンは非垞に効率的です。 さらに、出力語が圢成される入力文字の有限セットがありたす。 たた、各入力シンボルがマシンを新しい状態に移行するこずにも留意する必芁がありたす。 この堎合、入力状態は非同期操䜜の状態になり、この倀に基づいお、状態マシンは特定の状態を圢成し、それに応じおタスク出力ワヌドぞの反応を圢成したす。 このアプロヌチにより、非同期タスクの圢成ず管理が簡玠化されたす有限状態マシンに関する詳现情報は、むンタヌネット䞊に詳现な蚘事が倚数掲茉されおいたす。



ステヌトマシンはクラスの圢匏で圢成され、次のメンバヌ倉数が含たれたす。

  public int32 '<>1__state'; private int32 '<one>5__1'; public Mechanism_async.Program '<>4__this'; public System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> '<>t__builder'; private System.Runtime.CompilerServices.TaskAwaiter '<>u__awaiter';
      
      





すべおの倉数の名前には、コンパむラによっお名前が生成されるこずを瀺す山括匧が含たれおいたす。 これは、生成されたコヌドがナヌザヌコヌドず競合しないようにするために必芁です。正しいCでは、倉数名に山括匧を含めるこずができないためです。





コンパむラの内郚で実際に䜕が起こるかに぀いおのより詳现な研究のために、<MethodTaskAsync> d__0のコンパむラによっお生成されたILコヌドを怜蚎しおください。

ILコヌド
 .class nested private auto ansi sealed beforefieldinit '<MethodTaskAsync>d__0' extends [mscorlib]System.Object implements [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Fields .field public int32 '<>1__state' .field public valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> '<>t__builder' .field public class Asynchronous.Program '<>4__this' .field private int32 '<one>5__1' .field private valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter '<>u__1' // Methods .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { // Method begins at RVA 0x20ef // Code size 8 (0x8) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: nop IL_0007: ret } // end of method '<MethodTaskAsync>d__0'::.ctor .method private final hidebysig newslot virtual instance void MoveNext () cil managed { .override method instance void [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext() // Method begins at RVA 0x20f8 // Code size 185 (0xb9) .maxstack 3 .locals init ( [0] int32, [1] int32, [2] valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter, [3] class Asynchronous.Program/'<MethodTaskAsync>d__0', [4] class [mscorlib]System.Exception ) IL_0000: ldarg.0 IL_0001: ldfld int32 Asynchronous.Program/'<MethodTaskAsync>d__0'::'<>1__state' IL_0006: stloc.0 .try { IL_0007: ldloc.0 IL_0008: brfalse.s IL_000c IL_000a: br.s IL_000e IL_000c: br.s IL_0054 IL_000e: nop IL_000f: ldarg.0 IL_0010: ldc.i4.s 33 IL_0012: stfld int32 Asynchronous.Program/'<MethodTaskAsync>d__0'::'<one>5__1' IL_0017: ldc.i4 1000 IL_001c: call class [mscorlib]System.Threading.Tasks.Task [mscorlib]System.Threading.Tasks.Task::Delay(int32) IL_0021: callvirt instance valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter [mscorlib]System.Threading.Tasks.Task::GetAwaiter() IL_0026: stloc.2 IL_0027: ldloca.s 2 IL_0029: call instance bool [mscorlib]System.Runtime.CompilerServices.TaskAwaiter::get_IsCompleted() IL_002e: brtrue.s IL_0070 IL_0030: ldarg.0 IL_0031: ldc.i4.0 IL_0032: dup IL_0033: stloc.0 IL_0034: stfld int32 Asynchronous.Program/'<MethodTaskAsync>d__0'::'<>1__state' IL_0039: ldarg.0 IL_003a: ldloc.2 IL_003b: stfld valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter Asynchronous.Program/'<MethodTaskAsync>d__0'::'<>u__1' IL_0040: ldarg.0 IL_0041: stloc.3 IL_0042: ldarg.0 IL_0043: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> Asynchronous.Program/'<MethodTaskAsync>d__0'::'<>t__builder' IL_0048: ldloca.s 2 IL_004a: ldloca.s 3 IL_004c: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::AwaitUnsafeOnCompleted<valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter, class Asynchronous.Program/'<MethodTaskAsync>d__0'>(!!0&, !!1&) IL_0051: nop IL_0052: leave.s IL_00b8 IL_0054: ldarg.0 IL_0055: ldfld valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter Asynchronous.Program/'<MethodTaskAsync>d__0'::'<>u__1' IL_005a: stloc.2 IL_005b: ldarg.0 IL_005c: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter Asynchronous.Program/'<MethodTaskAsync>d__0'::'<>u__1' IL_0061: initobj [mscorlib]System.Runtime.CompilerServices.TaskAwaiter IL_0067: ldarg.0 IL_0068: ldc.i4.m1 IL_0069: dup IL_006a: stloc.0 IL_006b: stfld int32 Asynchronous.Program/'<MethodTaskAsync>d__0'::'<>1__state' IL_0070: ldloca.s 2 IL_0072: call instance void [mscorlib]System.Runtime.CompilerServices.TaskAwaiter::GetResult() IL_0077: nop IL_0078: ldloca.s 2 IL_007a: initobj [mscorlib]System.Runtime.CompilerServices.TaskAwaiter IL_0080: ldarg.0 IL_0081: ldfld int32 Asynchronous.Program/'<MethodTaskAsync>d__0'::'<one>5__1' IL_0086: stloc.1 IL_0087: leave.s IL_00a3 } // end .try catch [mscorlib]System.Exception { IL_0089: stloc.s 4 IL_008b: ldarg.0 IL_008c: ldc.i4.s -2 IL_008e: stfld int32 Asynchronous.Program/'<MethodTaskAsync>d__0'::'<>1__state' IL_0093: ldarg.0 IL_0094: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> Asynchronous.Program/'<MethodTaskAsync>d__0'::'<>t__builder' IL_0099: ldloc.s 4 IL_009b: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::SetException(class [mscorlib]System.Exception) IL_00a0: nop IL_00a1: leave.s IL_00b8 } // end handler IL_00a3: ldarg.0 IL_00a4: ldc.i4.s -2 IL_00a6: stfld int32 Asynchronous.Program/'<MethodTaskAsync>d__0'::'<>1__state' IL_00ab: ldarg.0 IL_00ac: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> Asynchronous.Program/'<MethodTaskAsync>d__0'::'<>t__builder' IL_00b1: ldloc.1 IL_00b2: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::SetResult(!0) IL_00b7: nop IL_00b8: ret } // end of method '<MethodTaskAsync>d__0'::MoveNext .method private final hidebysig newslot virtual instance void SetStateMachine ( class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine stateMachine ) cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance void [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine::SetStateMachine(class [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine) // Method begins at RVA 0x21d0 // Code size 1 (0x1) .maxstack 8 IL_0000: ret } // end of method '<MethodTaskAsync>d__0'::SetStateMachine } // end of class <MethodTaskAsync>d__0
      
      







MoveNextメ゜ッド



MethodTaskタむプ甚に生成されたクラスは、IAsyncStateMachineむンタヌフェむスを実装したす。これは、非同期メ゜ッド甚に䜜成されたステヌトマシンを衚したす。 このタむプは、コンパむラヌ専甚です。 このむンタヌフェむスには、MoveNextおよびSetStateMachineのメンバヌが含たれたす。 MoveNextメ゜ッドは、状態マシンを次の状態に移動したす。 このメ゜ッドには元のコヌドが含たれおおり、メ゜ッドの最初の入り口ず埅機の䞡方で呌び出されたす。 ステヌトマシンは、䜕らかの初期状態で䜜業を開始するず考えられおいたす。 最も単玔な非同期メ゜ッドを䜿甚しおも、MoveNextコヌドは驚くほど耇雑であるため、Cの同等のコヌドで可胜な限り正確に説明するようにしたす。



MoveNextメ゜ッドの名前は、以前のバヌゞョンのCの反埩子ブロックによっお生成されたMoveNextメ゜ッドず類䌌しおいるためです。 これらのブロックを䜿甚するず、yield returnキヌワヌドを䜿甚しお、単䞀のメ゜ッドでIEnumerableむンタヌフェむスを実装できたす。 この目的で䜿甚される有限状態マシンは、倚くの点で非同期状態マシンに䌌おいたすが、より簡単です。



䞭間コヌドを怜蚎し、その䞭で䜕が起こるかを確認したす以䞋では、コンパむラヌが生成するもののより完党な議論のためにCIL蚀語を完党に説明するこずにし、技術的な詳现をスキップできるようにすべおの呜什を説明したした

 .locals init ( [0] int32, [1] int32, [2] valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter, [3] class Asynchronous.Program/'<MethodTaskAsync>d__0', [4] class [mscorlib]System.Exception )
      
      









  IL_0000: ldarg.0 IL_0001: ldfld int32 Asynchronous.Program/'<MethodTaskAsync>d__0'::'<>1__state' IL_0006: stloc.0
      
      









  IL_0007: ldloc.0 IL_0008: brfalse.s IL_000c IL_000a: br.s IL_000e IL_000c: br.s IL_0054 IL_000e: nop IL_000f: ldarg.0 IL_0010: ldc.i4.s 33 IL_0012: stfld int32 Asynchronous.Program/'<MethodTaskAsync>d__0'::'<one>5__1' IL_0017: ldc.i4 1000 IL_001c: call class [mscorlib]System.Threading.Tasks.Task [mscorlib]System.Threading.Tasks.Task::Delay(int32) IL_0021: callvirt instance valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter [mscorlib]System.Threading.Tasks.Task::GetAwaiter() IL_0026: stloc.2 IL_0027: ldloca.s 2 IL_0029: call instance bool [mscorlib]System.Runtime.CompilerServices.TaskAwaiter::get_IsCompleted() IL_002e: brtrue.s IL_0070
      
      







したがっお、次のようなコヌドを想像できたす。

 public void MoveNext() { switch(this.1_state) { case -1: this.one = 33; var task = Task.Delay(1000); var awaiter = task.GetAwaiter(); //  ,     ,     (  IL-) if(!awaiter.IsCompleted) { ... return; } } ... //  }
      
      





䞊蚘のコヌドは、ステヌトマシンの初期状態を担圓し、非同期タスクの完了を確認し、メ゜ッドの適切な堎所に移動したす。 この堎合、オヌトマトンのいく぀かの状態の1぀ぞの移行が発生したす。メ゜ッドは埅ち合わせ堎所たたは同期終了で䞭断されたす。



䞀時停止方法



メ゜ッドが䞭断された堎所のILコヌドを怜蚎したす。

  IL_0030: ldarg.0 IL_0031: ldc.i4.0 IL_0032: dup IL_0033: stloc.0 IL_0034: stfld int32 Asynchronous.Program/'<MethosTaskAsync>d__0'::'<>1__state' IL_0039: ldarg.0 IL_003a: ldloc.2 IL_003b: stfld valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter Asynchronous.Program/'<MethosTaskAsync>d__0'::'<>u__1' IL_0040: ldarg.0 IL_0041: stloc.3 IL_0042: ldarg.0 IL_0043: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> Asynchronous.Program/'<MethosTaskAsync>d__0'::'<>t__builder' IL_0048: ldloca.s 2 IL_004a: ldloca.s 3 IL_004c: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::AwaitUnsafeOnCompleted<valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter, class Asynchronous.Program/'<MethosTaskAsync>d__0'>(!!0&, !!1&) IL_0051: nop IL_0052: leave.s IL_00b8
      
      





すべおが䞊蚘で説明されおいるように、各操䜜を説明する䟡倀はありたせん。



AsyncTaskMethodBuilder構造を詳しく芋おみたしょうこの構造ずそれに関連するすべおの研究に぀いおはいく぀かの蚘事で説明できるので、ここでは詳しく説明したせん。

  /// <summary>   default(TResult).</summary> internal readonly static Task<TResult> s_defaultResultTask = AsyncTaskCache.CreateCacheableTask(default(TResult)); /// <summary>,   IAsyncStateMachine.</summary> private AsyncMethodBuilderCore m_coreState; // mutable struct: must not be readonly /// <summary>  </summary> private Task<TResult> m_task; // lazily-initialized: must not be readonly /// <summary> ///       ,  awaiter  /// </summary> /// <typeparam name="TAwaiter">  awaiter.</typeparam> /// <typeparam name="TStateMachine">   .</typeparam> /// <param name="awaiter">The awaiter.</param> /// <param name="stateMachine"> .</param> [SecuritySafeCritical] public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>( ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine { try { AsyncMethodBuilderCore.MoveNextRunner runnerToInitialize = null; var continuation = m_coreState.GetCompletionAction(AsyncCausalityTracer.LoggingOn ? this.Task : null, ref runnerToInitialize); //    await,            if (m_coreState.m_stateMachine == null) { //         var builtTask = this.Task; //      internal-, //      . m_coreState.PostBoxInitialization(stateMachine, runnerToInitialize, builtTask); } awaiter.UnsafeOnCompleted(continuation); } catch (Exception e) { AsyncMethodBuilderCore.ThrowAsync(e, targetContext: null); } }
      
      





この構造の内郚にあるものを簡単に怜蚎しおください。



わずかに異なる゜ヌスコヌドを取埗したす。

 public void MoveNext() { switch(this.1_state) { case -1: this.one = 33; var task = Task.Delay(1000); var awaiter = task.GetAwaiter(); //  ,     ,     (  IL-) if(!awaiter.IsCompleted) { this.1_state = 0; this.u__awaiter = awaiter; //u__awaiter   TaskAwaiter t_builder.AwaitUnsafeOnCompleted(ref this.u_awaiter, ref <MethodTaskAsync>d__0); return; } } ... //  }
      
      





メ゜ッドの再開



このコヌドを実行した埌、呌び出し元のスレッドは自分の仕事に取り掛かりたすが、珟時点では、タスクが完了するのを埅っおいたす。タスクが完了するず、メ゜ッドが再び呌び出されMoveNextメ゜ッドメ゜ッド呌び出しでAwaitUnsafeOnCompleted仕事のために必芁なすべおを完了。続行するずきに呌び出されるILコヌドを考えたす。

  IL_0054: ldarg.0 IL_0055: ldfld valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter Asynchronous.Program/'<MethodTaskAsync>d__0'::'<>u__1' IL_005a: stloc.2 IL_005b: ldarg.0 IL_005c: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter Asynchronous.Program/'<MethodTaskAsync>d__0'::'<>u__1' IL_0061: initobj [mscorlib]System.Runtime.CompilerServices.TaskAwaiter IL_0067: ldarg.0 IL_0068: ldc.i4.m1 IL_0069: dup IL_006a: stloc.0 IL_006b: stfld int32 Asynchronous.Program/'<MethodTaskAsync>d__0'::'<>1__state' IL_0070: ldloca.s 2 IL_0072: call instance void [mscorlib]System.Runtime.CompilerServices.TaskAwaiter::GetResult() IL_0077: nop IL_0078: ldloca.s 2 IL_007a: initobj [mscorlib]System.Runtime.CompilerServices.TaskAwaiter IL_0080: ldarg.0 IL_0081: ldfld int32 Asynchronous.Program/'<MethodTaskAsync>d__0'::'<one>5__1' IL_0086: stloc.1 IL_0087: leave.s IL_00a3 IL_00a3: ldarg.0 IL_00a4: ldc.i4.s -2 IL_00a6: stfld int32 Asynchronous.Program/'<MethodTaskAsync>d__0'::'<>1__state' IL_00ab: ldarg.0 IL_00ac: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> Asynchronous.Program/'<MethodTaskAsync>d__0'::'<>t__builder' IL_00b1: ldloc.1 IL_00b2: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::SetResult(!0) IL_00b7: nop
      
      







結果は、おおよその゜ヌスコヌドです。

 public void MoveNext() { switch(this.1_state) { case -1: this.one = 33; var task = Task.Delay(1000); var awaiter = task.GetAwaiter(); //  ,     ,     (  IL-) if(!awaiter.IsCompleted) { this.1_state = 0; this.u__awaiter = awaiter; //u__awaiter   TaskAwaiter t_builder.AwaitUnsafeOnCompleted(ref this.u_awaiter, ref <MethodTaskAsync>d__0); return; } case 0: var awaiter = this.u_awaiter; this.u_awaiter = new System.Runtime.CompilerServices.TaskAwaiter(); this.1_state = -1; awaiter.GetResult(); awaiter = new System.Runtime.CompilerServices.TaskAwaiter(); var one = this.<one>5_1; this.1_state = -2; this.t_builder.SetResult(one); } }
      
      





同期完了



同期終了の堎合、メ゜ッドを停止しお再開しないでください。この堎合、メ゜ッドの実行を確認し、goto caseステヌトメントを䜿甚しお適切な堎所に移動するだけです。

 public void MoveNext() { switch(this.1_state) { case -1: this.one = 33; var task = Task.Delay(1000); var awaiter = task.GetAwaiter(); //  ,     ,     (  IL-) if(awaiter.IsCompleted) { goto case 0; } case 0: this.1_state = 0; ... } }
      
      





, , goto .



...



この蚘事では、Alex DavisによるC5.0の非同期プログラミングに関するお気に入りの本の1぀に䟝存したした。䞀般に、それは小さく必芁に応じお1日で読むこずができたす、非垞に興味深く、適床に詳现で非同期/埅機メカニズム党䜓を説明しおいるため、党員に読むこずをお勧めしたす。同時に、初心者にも読むこずができ、すべおがそこに非垞に簡単に曞かれおいたす人生の䟋など。それを読んで䞊行しおILコヌドを勉匷しおいるず、本に曞かれおいるものず実際にそこにあるものずの間にわずかな矛盟が芋぀かりたした。しかし、ほずんどの堎合、コンパむラが少し修正しおからわずかに異なる結果を生成し始めた可胜性が最も高いず思いたす。しかし、これはそれにこだわるほど重芁ではありたせん。同時に、゜ヌスコヌドずしおAsyncTaskMethodBuilderを説明するために、このリ゜ヌスを䜿甚したしたこれは、さらに深く掘り䞋げたいず思う人がいる堎合です。



All Articles