Skip to content

Instantly share code, notes, and snippets.

@kekyo
Last active July 8, 2019 00:51
Show Gist options
  • Save kekyo/59706c985206542f48faa3a435f27d9b to your computer and use it in GitHub Desktop.
Save kekyo/59706c985206542f48faa3a435f27d9b to your computer and use it in GitHub Desktop.
Task.Runで非同期APIをシミュレートすべきかどうかの判断

朝バタバタしてクリアじゃなかった... ちょっと間違ってましたこういうことです:

  • 多数同時並行するタスクがある場合
    • Windowsの場合はI/O完了ポートの「ブロックされたスレッドを検出するとワーカースレッドを世に放つ」機能があるので、同期APIがブロックしても、ワーカースレッド上限まではOK(ThreadPool.SetMaxThreadsの第二引数completionPortThreads)。
    • Windowsではない環境では必ず上記機能が使えるとは言えない(多分単純スレッドプール)ので、同期APIによるスレッドブロックが発生すると、同時並行動作数はそれ以上伸びない。これを避けたい場合、Task.Run を使わざるを得ない。
  • 多数同時並行したいタスクがない、GUIの場合
    • 同期APIでブロックすると、それがUIスレッドの場合はUIが固まってしまうので、それを避けたいなら Task.Run を使わざるを得ない。但し、継続処理がUIを操作する場合はUIスレッドにマーシャリングすることになり、そのコストはかなり高いことに注意(≒await後の処理でUI部品を操作する場合など)。
  • 多数同時並行したいタスクがない場合
    • 同期APIと非同期APIを比較すると、非同期APIのほうが余分なハンドリングを必要とするコストがあるので、この場合は同期APIをそのまま使うのがいい。

Taskを使うかValueTaskを使うかによる差については、本来はすべてをTaskを返す非同期APIとして定義したいが、ほとんどの場合同期的に完了してしまう(つまり一瞬で操作が完了する、待機する可能性が0ではないが殆ど待機しないというような)処理を、いつもTaskで管理するのはコストが高いので、代わりにValueTaskを使って初めから完了しているものはコストをほとんど0とするようにするという話です。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment