2017年6月4日日曜日

async/await について

async/await

await XxxxAsync();
と記述した時、XxxxAsync() が終了するまで制御をOSに返し、
それ以降の実行を待機する仕組み

async 関数を await で実行

void を返す      ... fire & forget
Task<int> を返す   ... 非同期処理完了後に同期して int を返す
Task  を返す     ... 非同期処理完了後に同期して void を返す

fire & forget とは

await XxxxAsync(); と、その下に続くコードが並列実行される
(ノンブロッキング関数的なイメージ)

await

await XxxxAsync(); の下に続くコードは、
XxxxAsync() から戻ってきた後に実行されるコールバックとしてコンパイルされる。
コールバックが実行されるスレッドを決定するのが同期コンテキスト。

同期コンテキスト(synchronization context)

Task オブジェクトがタスク実行後に戻る文脈を保持する。
await 呼び出し側の SynchronizationContext.Current に戻ってくるように設定される。
デフォルトでは task.ConfigureAwait( true ) となっており、同期コンテキストが適用される。

実行環境による同期コンテキストの違い

WPF等GUI  … UIスレッド
ASP.NET    … リクエストとレスポンスが同一スレッド
コンソール   … null(同期コンテキストが存在しない)
※同期コンテキストが存在しない
  = 戻るべきスレッドを規定しない
  = スレッドプールの任意のスレッドに戻る(というか移行)

同期コンテキストを無視したいとき

await XxxAsync().ConfigureAwait( false );
コンソールと同じ動作となる

単に、何かの処理を別スレッドで実行したい場合について

await/async で、せっかくコールバックをインデントのネストから解放できたのに、
任意の処理を別スレッドでさせたいときなんかに Task.Run() で処理を書かざるを得ないのはダサく感じる。
平坦に書きたいです。

同期コンテキストがなければ await Task.Yield() でそれ以降を別スレッドに移せるぽいが、
そうでない場合は await Task.Run( () => {} ).ConfigureAwait( false ); などと書かないとダメかも。
でも無意味なタスクオブジェクトが発生したりしそう。

そもそも、async/await は非同期タスクを待ち受けるための構文であって、
スレッド実行を平坦に記述するという汎用的な目的で使うべきものではない、ということか。
同期させるスレッドを自由に切り替えできればいいのにと思うけど、そういう思想のものじゃない、のか…。

ニューラルネットやってみてる

最近ニューラルネットやってみてる 理屈を学ぼうと思って、まずはオブジェクト的に作ってみてる (ベクトル化とかは後回しで) sigmoid, tanh, ReLU MSE, cross entorpy あたりを小規模にいじってみてます でも今 soft max の逆伝...