同期IO (Windows)
- ワーカースレッドに逃がせば非同期的に扱うこともできなくはない
- スレッドごとにハンドルを用意しないと、パフォーマンスが低下する?
- ハンドルがオフセットを管理するので、共有するなら排他処理が必須
- それ以前に、内部で色々と排他処理しているので、並列動作しないのでは?
Overlapped IO (Windows)
- 同期IOのAPIをそのまま活用する
- 条件や状況によっては非同期にならない場合がある
API
CreateFile- ファイルを作ったり開いたりする
FILE_FLAG_OVERLAPPEDフラグを加えると、そのファイルのIOが非同期になる
ReadFile- データを読み出す
- オフセット値や完了通知用イベントを
OVERLAPPEDで渡す- イベントは、処理開始時にリセットされ、処理完了時にセットされる
- IO処理がその場で完了すると、
TRUEを返す- このとき、読み出したバイト数も一緒に返される
- IO処理が完了しなければ、
FALSEを返す- 正常に保留された場合、
GetLastErrorがERROR_IO_PENDINGを返す
- 正常に保留された場合、
GetOverlappedResult- IO処理が完了したか調べる
- 完了時、読み出したバイト数も一緒に返す
CancelIoEx- IO処理を取り消す
- 指定のファイルでのIO処理すべてを取り消すこともできる
メモ
OVERLAPPEDオブジェクトは処理が完了するまで、変更・解放・再利用のいずれもしてはいけない- すなわち、
OVERLAPPEDを格納したメモリは指定のIO処理専用として寿命をともにすると良い?
- すなわち、
OVERLAPPEDのイベントハンドルはNULLにもできるが非推奨- そうした場合、ファイルハンドルで完了通知を行うため、個々のIO処理の完了を認識できなくなる
- 非同期IOとして呼び出しても同期IOになる場合がある:
- NTFS圧縮やNTFS暗号化されたストレージは非同期にアクセスできない
- サイズ延長を伴う書き込みは同期的に行われる
- キャッシュを介すると、同期IOになる場合がある:
- キャッシュにヒットした場合、即座に制御が返るので同期IOのように見える
- キャッシュにヒットしなかった場合、ページフォルト機構は同期的に行われる
- 処理をワーカースレッドに逃がしたりもするが、用意されるスレッド数は多くないため、立て続けにIO処理を投げると同期処理になる
- 必ず非同期にしたいなら、キャッシュを通らなければ良い
FILE_FLAG_NO_BUFFERINGフラグを立てると、データをメモリにキャッシュしなくなる- その場合、オフセットやバッファメモリのアライメントをストレージに揃える必要がある
IO Ring (Windows)
- Windows 11の21H2 (Build 22000)で導入された新しいAPI
- 事前準備や一括処理によってオーバーヘッドを削減できる
- 完了通知も一括して行われるため、サブミットの粒度や頻度に気をつける必要がある
API
CreateIoRing- サイズを指定して、キューを生成する
- 処理提出用と完了通知用の2つのキューがある
BuildIoRingRegisterBuffers/BuildIoRingRegisterFileHandles- バッファメモリ/ファイルハンドルのリストを登録する処理をキューに追加する
- 登録の際、以前に登録したリストは完全に上書きされて利用できなくなる
BuildIoRingReadFile- データを読み出す処理をキューに追加する
- 登録済みのバッファメモリ/ファイルハンドルをリストのインデックスで指定できる
SubmitIoRing- キューに追加した処理をカーネルに提出する
- 指定数の処理を完了する、または、指定時間を経過する、まで待機できる
BuildIoRingCancelRequest- 処理を取り消す処理をキューに追加する
- 設定された
userDataの値と一致する処理を対象とする
PopIoRingCompletion- 完了通知をキューから取り出す
- 処理の識別は設定された
userDataの値から行う
SetIoRingCompletionEvent- 完了通知キューが空でなくなったことを通知するためのイベントをセットする
- セットできるイベントは最大1つ
- イベントハンドルは内部で複製されるので、ユーザー側は閉じても良い
メモ
- バッファメモリやファイルハンドルを事前に登録することで、検証によるオーバーヘッドを登録時の一度だけにできる
- 複数のIO処理を一度のシステムコールで発行できるので、従来のAPIと比較してオーバーヘッドを削減できる
- 提出される処理は
userDataで渡す値を一意にすることで個体を識別できるようになる - Linuxにおけるio_uringというほぼ同等の機能をもとに作られているため、マルチプラットフォーム対応がし易い、かもしれない