Open棟梁Project - マイクロソフト系技術情報 Wiki

目次

概要

awaitの意味は、スレッドを留めずにCallbackを待つということらしい。
async/awaitはそういう動きをする、非同期プログラムを容易に記述できる。

非同期処理の実装史

1. Thread、ThreadPool?

従来の、マルチスレッド・プログラミング。

2. APM、EAP (Control.Invoke、.BeginInvoke?)

「Windowsメッセージングキュー(Control.Invoke、.BeginInvoke?)」による方式。

Open棟梁の「非同期呼出フレームワーク」がこの方式で実装されている。

3. TAP (async/await)

async/awaitは、TAP(Task-based Asynchronous Pattern)の方式で実装されている。

用途

使い方

余談?

async/awaitの夫々の意味。

この動作は想像し難いが、具体的には、

というイメージ。

なので、言葉尻で動作を想像し難い。

タスク分割方法

await(Task.Run)を切れ目として、
プログラマが意識して時間のかかるバックグラウンド処理
(ネットワーク バインドまたは I/O バインドの処理)を分割する。

仕組み

4. Reactive Extensions(Rx)

使い方

非同期メソッドの戻り値

void型

Fire & Forgetの場合、戻り値は不要。

Task型

Awaitableの場合、

Task<T>型

Awaitableの場合、

Task.FromResult?

Task.FromResult?を使用すると、

詳細については、下記を参照。

非同期メソッドの呼び出し

Task.Run()、Task.Wait()メソッド

Task.WhenAll?()

await演算子

詳細

ここでは、

組み合わせによって、await後の処理が、
どのように実行されるのかについて説明する。

非同期メソッドの種類

非同期メソッドには、2種類ある。

Fire & Forget

戻り値がvoidの「待てない」メソッド

Awaitable

戻り値がTask(もしくはTask<T>)の、await演算子かWait()メソッドで「待てる」メソッド

同期コンテキスト

実行環境によって持つ同期コンテキストの種類が異なる。

GUIアプリケーション

GUIアプリケーションでの同期コンテキストは
「Windowsメッセージングキュー(Control.Invoke、.BeginInvoke?で使う)」になる。

Consoleアプリケーション

Consoleアプリケーションでの同期コンテキストは「null」になる。

ThreadPool?

Task.Runを使用した場合の同期コンテキストは、
マルチスレッド環境下の「ThreadPool?」になる。

ASP.NET

ASP.NETアプリケーションでの同期コンテキストは
マルチスレッド環境下の「System.Threading.SynchronizationContext?.Current」になる。

詳しくは、非同期Controllerを参考にする。

この辺の

スタック・トレースを見ると、

同じ事らしいと解る。

並列実行

並列実行を始めるので、

特に、Consoleアプリケーションの同期コンテキスト(null)の下では、
新規に同期処理の実装が必要になることがある。

同期

async/awaitは非同期呼び出しで投げっぱなした後に、
同期コンテキストにより同期される方式のため、同期をあまり考慮していないが、
同期コンテキストによっては、同期を行う必要があるため、以下に注意する。

仕組みから

スレッドを使用した処理を記述しないが、

分割されたタスクは、

このため、一連の処理が(分割されたタスクが)、

スレッド同期ツールキットは使用不可

従って、スレッド同期のlock等は無意味。
従来のスレッド同期ツールキットは使用不可。

lock/mutex/semaphoreはtaskで全て使用禁止

旧プログラムで、

  1. スレッド・アフィニティのあるロック機構(lock/mutex/semaphore)
    を使用してコードブロックをロックしている場合に、
  2. awaitを使用して追加開発をしたい場合、
    (await演算子を含むコードブロックをロックしたい場合)、

SemaphoreSlim?を使用するように修正が必要になる。

WaitFor?[Single|Multi]Objectは例外的に使用可

Win32の待機関数のWaitFor?[Single|Multi]Objectは例外的に使用可。

これは、これらの待機関数は、

待つ関数であるためと考える。

その他

進捗報告

上記の仕組みで動いているとすると、進捗報告をどう実装するかが?であるが、
以下を見ると、Progressクラス、IProgress<T>インターフェースを使用するらしい事が解る。

詳しい仕組みは不明だが、GUI上で動作しているため、
同期コンテキストのControl.Invoke、.BeginInvoke?を使用しているものと思われる。

ContinueWith?

ConfigureAwait?

ガイドライン

以下の参考資料を纏めてみた。

一般的に

UIで Task.Wait() を使う場合は注意する

戻り値がvoidのメソッドを非同期呼び出ししない。

ライブラリの場合

ライブラリ内でTask.Runを使わない

Waitを使う同期メソッドで非同期メソッドをラップしない

これは以下の様なユーザの過程に基づくため。

デッドロックとSynchronizationContext?

性能

メモリ

非同期メソッドの呼び出しは次の3つのメモリ確保処理を生む。

ステートマシンとデリゲートはawaitキーワードがランタイムに
現れたときに作成されるため、同期処理と比べるとコストになる。

参考

落とし穴

参考

参考


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS