[[Open棟梁Project>http://opentouryo.osscons.jp/]] - [[マイクロソフト系技術情報 Wiki>http://techinfoofmicrosofttech.osscons.jp/]] * 目次 [#l24f314e] #contents *概要 [#d9ab14bf] -async/awaitの登場で、マルチスレッド処理として実装しなくても、~ 非同期処理を同期型処理と、ほぼ変わらない記述で実装可能になった。 -非同期処理はスレッドやWindowsメッセージングキューでTask化される。~ 昔懐かしい、[[ノンプリエンプティブ・マルチタスク]](Win3.1)のようなイメージ。 **スレッド [#c79c02e2] -スレッドの並列実行はOSが裏で無意識にしてくれていた。 --タイムスライスで細切れ/ラウンドロビンで論理的に並列実行。 --CPUのコア数に応じて、物理的に並列実行。 -しかし、以下の処理は意識的に実装する必要があった。 --非同期処理をスレッド関数として分離して実装する。 --スレッド関数を作成したワーカースレッドに渡す。 --スレッド関数の結果をメインスレッドで待ち合わせる。 **タスク [#ae25c1af] -Taskを返す非同期メソッドを、 --asyncで修飾したメソッドから、awaitステートメントを付与して呼び出す。 --若しくは、Task.Run()で実行して、Task.Wait()で待ち合わせる。 ***用途 [#kb0ddc1e] -主に、UIスレッドのハングアップを防止するために使用される。 -UIスレッドから、時間のかかるバックグラウンド処理~ (ネットワーク バインドまたは I/O バインドの処理)を分離する。 -この仕組みは、Webサーバのスレッド枯渇を防ぐ[[非同期コントローラ>ASP.NET MVCの用語#lc319892]]などにも応用されている。 ***タスクの分割 [#gb4b4431] awaitを切れ目として、プログラマが意識して時間のかかる~ バックグラウンド処理(ネットワーク バインドまたは I/O バインドの処理)を分割する。 -await前の処理はフォアグラウンドで実行される。 -awaitで呼び出す非同期メソッドはバックグラウンドで実行される。 -await後の処理は、コールバックとして実装せずにフォアグラウンドに復帰する。 ***詳細 [#kaa7ba64] -非同期化は、スレッドやWindowsメッセージングキューなどを使用して行われる。 -await、Task.Wait()の待ち合わせまでがセットになっている仕組みなので、~ 並列実行処理を実装するための基盤ではないことに注意。 *使い方 [#nf166e6d] -async/awaitの登場で、同期型処理と、ほぼ変わらない記述で実装可能になった。 -しかし、デバッグの時は非同期で実行されていることを意識する必要がある。 **非同期メソッドの戻り値 [#b43ff41c] ***void型 [#w5cf9ec2] -戻り値としてreturn文を書かない場合 -「イベント・ハンドラかどうか」→ void型 ***Task型 [#t98c2e31] -戻り値としてreturn文を書かない場合 -「待機したいかどうか」→ Task型 ***Task<T>型 [#td2f6464] -非同期処理の結果を受け取りたい場合 -戻り値はTask<T>型だが、returnするのはT型の値 **非同期メソッドの呼び出し [#s278988c] ***Task.Run()、Task.Wait()メソッド [#l8b4142b] -Task.Run() --非同期メソッドを実行してTask、Task<TResult>を返す。 -Task.Wait() --Task、Task<TResult>の実行が完了するまで待機する。 ***await演算子 [#z7b2e8a4] -Task の実行が完了するまで待機する。 --await 非同期メソッド() --await Task.Run() -await演算子の使い方 --非同期メソッドを呼び出すときに、await演算子(後述)を利用する。 --メソッド内でawait演算子(後述)を利用する場合、async修飾子でメソッドを修飾する。 --await演算子は、async修飾子の付くメソッドの中で1つ以上記述できる。 **その他 [#r19de18d] ***Task.WhenAll() [#j18f876f] -Task.WhenAll()メソッドで複数のタスクを待機するタスクを取得する。 -このTaskをTask.Wait()するとTask毎の例外をAggregateException型として取得可能。 ***進捗報告 [#p80858da] 上記の仕組みで動いているとすると、進捗報告をどう実装するかが?であるが、~ 以下を見ると、Progressクラス、IProgress<T>インターフェースを使用するらしい事が解る。 -非同期メソッド - C# によるプログラミング入門 | ++C++; // 未確認飛行 C~ http://ufcpp.net/study/csharp/sp5_async.html#cancel -.NET TIPS:WPF/Windowsフォーム:~ 時間のかかる処理をバックグラウンドで実行するには?(async/await編)[C#/VB] - @IT~ http://www.atmarkit.co.jp/ait/articles/1512/02/news019.html *スレッド同期 [#w87411f4] **仕組みから [#ab98fed9] スレッドを使用した処理を記述しないが、分割されたタスクは、 -同一スレッドで動作することも -別スレッドで動作することもある。 このため、一連の処理が(分割されたタスクが)、 -異なるスレッドで実装される保証は無い。 -同じスレッドで実行される保証も無い。 **スレッド同期ツールキットは使用不可 [#sdd9c0ad] 従って、スレッド同期のlock等は無意味。~ 従来のスレッド同期ツールキットは使用不可。 ***lock/mutex/semaphoreはtaskで全て使用禁止 [#offf1b54] -旧プログラムでmutex使ってる場合に、awaitで追加開発したいときは、SemaphoreSlimに修正が必要 -.NET TIPS:非同期:awaitを含むコードをロックするには?(SemaphoreSlim編)[C#、VB] - @IT~ http://www.atmarkit.co.jp/ait/spv/1411/11/news117.html --SemaphoreSlim.WaitAsync関数もasync/awaitする。 --つまり、Semaphoreによるlockさえ、タスクとして分割されて待機/実行される。 ***WaitFor[Single|Multi]Objectは例外的に使用可 [#z135f913] これは、Win32の待機関数のWaitFor[Single|Multi]Objectは、~ スレッドに限らず様々な「オブジェクト」の状態が変化する(シグナル状態になる)のを待つ関数であるためと考える。 --ThreadPool.RegisterWaitForSingleObject メソッド (System.Threading)~ https://msdn.microsoft.com/ja-jp/library/system.threading.threadpool.registerwaitforsingleobject *参考 [#l0e9a88c] -Tasks are (still) not threads and async is not parallel~ http://blogs.msdn.com/b/benwilli/archive/2015/09/10/tasks-are-still-not-threads-and-async-is-not-parallel.aspx -c# - Wrapping ManualResetEvent as awaitable task - Stack Overflow~ http://stackoverflow.com/questions/18756354/wrapping-manualresetevent-as-awaitable-task -Insider.NET > 業務アプリInsider > 連載:C# 5.0&VB 11.0新機能「async/await非同期メソッド」入門 - @IT~ http://www.atmarkit.co.jp/ait/subtop/features/dotnet/app/masterasync_index.html