知識マップ: Windows I/Oの深層(第3回) ── I/O完了ポート(IOCP)と.NETスレッドプール:async/awaitの地下室

記事「Windows I/Oの深層(第3回) ── I/O完了ポート(IOCP)と.NETスレッドプール:async/awaitの地下室」の主張を、概念と関係(エッジ)に分解した知識グラフの全体です。各関係には根拠・確認日・確度が付いています。

I/O完了ポート(IOCP)は、非同期I/Oの完了パケットをFIFOのキューに集約しつつ、実行可能なスレッド数をコンカレンシー値以下に抑えるスケジューリング機構でもあります。待機スレッドはLIFOで起こされるため、忙しいときほど同じスレッドが回り続けてコンテキストスイッチを抑えられます。.NETスレッドプールはワーカースレッドとI/O完了スレッドの2階建てで、非同期ハンドルはThreadPoolBoundHandle経由でプール自身のIOCPに結び付き、awaitのI/O待ちにスレッドは存在せず完了後の継続だけがスレッドに乗ります。継続の行き先は捕捉されたSynchronizationContext次第で、ConfigureAwait(false)は捕捉をやめる指示にすぎません。継続やワーカーへの同期待ちの混入(sync-over-async)は、スレッドプール飢餓の主因です。

I/O完了ポート(IOCP)と.NETスレッドプールの知識マップI/O完了ポートが完了通知のFIFOキューと実行可能スレッド数の制御(コンカレンシー値)を一体化していること、待機スレッドがLIFOで起こされること、CompletionKeyとOVERLAPPEDによる完了パケットの識別、.NETスレッドプールがワーカースレッドとI/O完了スレッドの2階建てでThreadPoolBoundHandle/NativeOverlappedを介してIOCPに結び付くこと、awaitの継続先がSynchronizationContextとConfigureAwait(false)で決まること、同期待ちの混入がスレッドプール飢餓を招くことを示す図利用する利用する利用する利用する前提とする前提とする前提とする利用するで構成できる利用する利用する推奨される対応利用する利用する利用する前提とする利用する実装を担う前提とする利用する利用する両立しない原因になり得る用いるのは非推奨前提とする利用するで確認できるで確認できる原因になり得る前提とする利用する利用する前提とするI/O完了ポート(IOCP).NETスレッドプールCompletionKeyCreateIoCompletionPortGetQueuedCompletionStatusOVERLAPPED構造体GetQueuedCompletionStatusExPostQueuedCompletionStatusコンカレンシー値Windowsスレッドプールの I/O APIOverlapped I/Oワーカースレッド(.NET)I/O完了スレッド(.NET)ThreadPoolBoundHandle.BindHandleNativeOverlappedFileOptions.Asynchronous非同期I/OSynchronizationContextConfigureAwait(false)同期待ちの混入(sync-over-async)スレッドプール飢餓(starvation)Task.RunLIFOスレッド解放ThreadPool.GetAvailableThreadsERROR_OPERATION_ABORTED見せかけの非同期ファイルハンドル

概念間の関係(全33件)

図と同じ関係を文章でも列挙します。表示している文と機械可読な意味データ(RDFa)は同じ要素に載っています。確度が「確立した関係」のものは直接の関係として、「条件付きの関係」のものは成立条件つきの言明(rdf:Statement)として表現しています。

主要概念の定義

I/O完了ポート(IOCP)
多数の非同期I/Oの完了通知を1つのFIFOキューに集約しつつ、実行可能なスレッド数をコンカレンシー値以下に保つスケジューリング機構を兼ねる、Windowsカーネルの仕組み。
.NETスレッドプール
.NETランタイムが提供する、ワーカースレッドとI/O完了スレッドの2階建てのスレッドプール。非同期I/Oのハンドルは内部で自前のI/O完了ポートに結び付けられる。
GetQueuedCompletionStatus
I/O完了ポートのキューから完了パケットを1つ取り出すWin32 API。戻り値がFALSEでもOVERLAPPEDポインターが非NULLなら、失敗したI/Oの完了パケットを取り出せたことを意味する。
GetQueuedCompletionStatusEx
複数の完了パケットを一度にまとめて取り出せるGetQueuedCompletionStatusの拡張版。高頻度I/Oで呼び出し回数を減らせる。
PostQueuedCompletionStatus
非同期I/Oを開始せずに、アプリケーション独自の完了パケットをI/O完了ポートのキューへ積めるWin32 API。ワーカーへの仕事依頼やシャットダウン指示に使う。
コンカレンシー値
I/O完了ポートに関連付いた「実行可能なスレッド数」の上限。CreateIoCompletionPortのNumberOfConcurrentThreadsで指定し、0ならシステムのプロセッサ数が使われる。全体としての最良の最大値はCPU数とされる。
Windowsスレッドプールの I/O API
内部でIOCPを使いながらスレッドの生成・管理を肩代わりする、新規のサーバーアプリケーション向けに推奨されるAPI群。
ThreadPoolBoundHandle.BindHandle
OSのハンドルをシステムスレッドプール(のI/O完了ポート)に結び付ける.NETの低レベルAPI。束縛したハンドルへの非同期I/OはNativeOverlappedと組み合わせて行う。
NativeOverlapped
Win32のOVERLAPPED構造体を.NET側で表現した構造体。ThreadPoolBoundHandleに束縛したハンドルへの低レベルの非同期I/Oで使う。
FileOptions.Asynchronous
.NETのFileStreamコンストラクターやFile.OpenHandleで、OSレベルの非同期I/O(FILE_FLAG_OVERLAPPED)を有効にする指定。ハンドルのモードを直接決める。
I/O完了スレッド(.NET)
.NETスレッドプールが提供する、非同期I/Oの完了を受け取って継続をスケジュールするスレッド群。ワーカースレッドとは別に管理される。
非同期I/O
要求を発行した呼び出しがI/Oの完了を待たずにすぐ戻り、完了を別途の通知(イベント・APC・I/O完了ポートなど)で受け取るI/Oの形態。
ConfigureAwait(false)
awaitの継続を、捕捉したSynchronizationContextやTaskSchedulerへ投げ返さないことを指示する.NETの記法。「必ずスレッドプールへ移る」保証ではない。
同期待ちの混入(sync-over-async)
非同期処理の継続やワーカーの中で、同期I/OやTask.Result/Wait()のような同期的な待ちを行ってしまうアンチパターン。スレッドプール飢餓の主因になる。
Task.Run
CPUを使う処理を.NETスレッドプールのワーカースレッドへ明示的にオフロードするためのAPI。I/OバウンドのTaskに使う必要はない。
スレッドプール飢餓(starvation)
同期待ちの混入などでスレッドプールのスレッドが塞がり続け、負荷がかかった瞬間に「継続を実行したいのに実行するスレッドがない」状態に陥ること。
見せかけの非同期
同期モードのハンドルに対してReadAsync/WriteAsyncを呼んだ結果生じる状態。呼び出し元はブロックされないが、裏でスレッドプールのスレッドが同期読み書きを肩代わりして待つ。
CreateIoCompletionPort
I/O完了ポートの新規作成と、既存ポートへのハンドルの関連付けの両方を行うWin32 API。NumberOfConcurrentThreadsでコンカレンシー値を指定する。

機械可読データ

このページはサイトの知識グラフ(_data/knowledge/)から自動生成されています。誤りの指摘はお問い合わせからお願いします。