C# のお手軽非同期プログラミング、async / await。
概念なり捉え方なりについては Taskを極めろ!async/await完全攻略を初めとした親切丁寧な記事があって、ふむふむなんて思っていたのだが、たまに、async / await してるのに妙に UI がフリーズしてないか、みたいな時があった。
そこで、async / await の実行タイミングを追うためのテストプログラムを作ってみた。
async な関数の中でさらに async な関数を呼びだして、それをいくつかのパターンでやってみた結果、たぶん実行タイミングのイメージは以下のような感じなのかなと。

SomeAsync() の中では Task.Run() しているわけではないので、直ちに非同期処理になるわけではなく、Code P~R は順次実行される。ここが重いと UI がフリーズする。
await に到達した段階で、それ以降 Code U までをタスクとして返す。仮に AnotherAsync() の中で Task.Run() していると、その部分は非同期に処理されるので、重くても UI はフリーズしない(テストプログラムでは Web から文字列を読み込む部分が非同期に処理される)。
メインルーチンに注目すると、よくあるのは
await SomeAsync();
で直ちに await するパターンだが、上図のように await を後ろまで引っ張ると、await まではすぐに実行される。await に到達した段階で、Code U までのタスクが終了するのを待つ。
~Async() の中ではひたすら Task.Run() すれば UI はフリーズしないが、他の async を呼ぶために async にしている場合は、その他のコードが重くないか考える必要がある。
ちなみに Code S~U が重い場合は、メインルーチンで await task している時に UI がフリーズする。
……っていう感じで合っているだろうか?