Task.Waitの問題点

Task.Waitはスレッドをロックする

非同期処理の完了を待つ方法には「Task.Wait」と「await」がある。このふたつはどう違うか。async/awaitを解説したスライドのページのひとつで、Task.Waitとawaitの違いが端的に説明されていた。

t.Wait();

  • wait for t: 類義語はstay(とどまる)
  • スレッドを止めて待つ

await t;

  • await t: 類義語はextpect(期待する)
  • スレッドを止めずにコールバックを待つ

An other world awaits you

だから、非同期処理の進捗をプログレスバーに表示したいときUIスレッドでTask.Waitしちゃうとうまくいかないです。(←やっちゃったひと。ちなみに、非同期処理からの進捗報告はProgress<T>を使うと楽でした。)

awaitとデッドロックになる

Task.Waitが非同期処理中にスレッドをブロックしてしまう(その間UIは更新できない)というのも困るが、もっと困るのがその非同期処理の中にawaitがある場合で、デッドロックが起きる。その原因をとても分かりやすく説明した図がこちらのページにある。

(文章は引用元を明記すれば許されるとは思うけど画像はちょっと気が引けるのでリンクだけ。)

awaitの処理の流れはこうなっていて、内部処理の話でも書いたが、await以降の処理を非同期処理の完了後に行うよう登録したら元のスレッドに戻ろうとする。ところがTask.Waitで元のスレッドがブロックされてて戻れない。戻らないからTask.Waitは待ち続ける、待ち続けるから戻らない……というデッドロックに陥る。Task.Waitとawait、それぞれの挙動を知っていないとハマってしまう。(←ハマったひと)

というわけで、Task.Waitはあまり使わない方がいいという話。

でも、いちいちメソッドの頭にasyncをつけないといけない(そしてつけたらつけたでawaitを書くまでインテリセンスがなんかちょっと不満そうにしてる)awaitよりも、何か手軽な感じがあって、つい使ってしまう。(←懲りないひと)

参考ページ