asyncとawaitとtaskとthread

超絶勘違いをしていた。


asyncとawaitキーワードを指定して非同期処理をしてもマルチスレッドになるわけではない。


てっきりマルチスレッドになるもんだと思ってた。
その割にスレッドIDが変わらないのは何だかな〜と不思議に思ってた。


asyncキーワードをつけたメソッドを呼び出すと、そのメソッドは1つのTaskとしてThreadPoolのキューに入れられ、すぐに実行される。
さらにawaitキーワードをつけて呼び出すと、そのawait以降の処理は別のTaskとしてThreadPoolのキューに入れられ、呼んだメソッドが終了するまでブロックされる。
awaitキーワードをつけずに呼び出すと、それ以降の処理が別のTaskとしてThreadPoolのキューに入れられるところまではawaitをつけた場合と同じだが、いつ実行されるかはフレームワークのスケジューリング任せ。
でいいのかな?


Taskとスレッドは1:1になるわけではない。
Taskはコードによって明示的/暗黙的に作られるが、スレッドは必要に応じてosが作る。
ThreadPoolクラスである程度コントロールはできるらしい。
Task.Run()やTask.Factory.StartNew()を使ってTaskを作ると新しいスレッドが作られるらしいが、これは保証されてることなのかな?
たまたまなのかな?


TaskはThreadPoolのキューに入れられ、空いているスレッドによって実行される。
1つのスレッドが同時に実行できるTaskは1つだけ。
コードの中にawaitがあると、コンパイラによってawait以降は別のTaskに分かれているので、スレッドは今のTaskが完了したとして、別の(おそらくはawait対象の)Taskを実行する。
そのTaskが完了するとawait以降のTaskが実行されるが、その時のスレッドはawaitまでを実行していたスレッドとは限らない。
ただ感覚としてはTask.Run()やTask.Factory.StartNew()を使わない限り、新しくスレッドが作られることはほとんどない。
1つないし2つのスレッドがすべてのTaskを処理しているらしい。


await/asyncの使用によってシングルスレッドでも非同期処理やその待機ができるわけだが、UIに関係ない処理は別スレッドに分けたほうが多少速い気がする。