I/O 完成埠

I/O 完成埠提供有效率的執行緒模型,可在多處理器系統上處理多個非同步 I/O 要求。 當進程建立 I/O 完成埠時,系統會針對唯一用途為服務這些要求的執行緒建立相關聯的佇列物件。 處理許多並行非同步 I/O 要求的進程可以透過搭配預先配置的執行緒集區使用 I/O 完成埠,比起在收到 I/O 要求時建立執行緒,更快速且有效率地執行此動作。

I/O 完成埠的運作方式

CreateIoCompletionPort函式會建立 I/O 完成埠,並將一或多個檔案控制代碼與該埠產生關聯。 當其中一個檔案控制碼上的非同步 I/O 作業完成時,I/O 完成封包會排入先出 (FIFO) ,以便與相關聯的 I/O 完成埠排入佇列。 這項機制的其中一個強大用途是將多個檔案控制代碼的同步處理點結合成單一物件,但也有其他有用的應用程式。 請注意,當封包依 FIFO 順序排入佇列時,它們可能會以不同的順序取消佇列。

注意

這裡所使用的 檔案控制碼 一詞是指代表重迭 I/O 端點的系統抽象概念,而不只是磁片上的檔案。 例如,它可以是網路端點、TCP 通訊端、具名管道或郵件位置。 任何支援重迭 I/O 的系統物件都可以使用。 如需相關 I/O 函式的清單,請參閱本主題結尾。

 

當檔案控制碼與完成埠相關聯時,在封包從完成埠移除之前,傳入的狀態欄塊將不會更新。 唯一的例外狀況是原始作業以同步方式傳回錯誤。 執行緒 (主執行緒或主執行緒本身所建立的執行緒) 會使用 GetQueuedCompletionStatus 函式來等候完成封包排入 I/O 完成埠,而不是直接等候非同步 I/O 完成。 在 I/O 完成埠上封鎖其執行的執行緒會以上一次先出 (LIFO) 順序發行,而下一個完成封包會從該執行緒的 I/O 完成埠 FIFO 佇列提取。 這表示,當完成封包釋放至執行緒時,系統會釋放與該埠相關聯的最後一個 () 執行緒,並傳遞最舊 I/O 完成的完成資訊。

雖然任何數目的執行緒可以針對指定的 I/O 完成埠呼叫 GetQueuedCompletionStatus ,但當指定的執行緒第一次呼叫 GetQueuedCompletionStatus 時,它會與指定的 I/O 完成埠相關聯,直到發生三件事之一:執行緒結束、指定不同的 I/O 完成埠,或關閉 I/O 完成埠。 換句話說,單一線程最多可以與一個 I/O 完成埠相關聯。

當完成封包排入 I/O 完成埠時,系統會先檢查與該埠相關聯的執行緒數目正在執行。 如果執行的執行緒數目小於下一節 () 所討論的並行值,則允許 (最近一個) 處理完成封包的其中一個等候執行緒。 當執行中的執行緒完成其處理時,通常會再次呼叫 GetQueuedCompletionStatus ,此時它會以下一個完成封包傳回,或在佇列是空的時等候。

執行緒可以使用 PostQueuedCompletionStatus 函式,將完成封包放在 I/O 完成埠的佇列中。 如此一來,除了從 I/O 系統接收 I/O 完成封包之外,完成埠也可以用來接收來自進程其他執行緒的通訊。 PostQueuedCompletionStatus函式可讓應用程式將自己的特殊用途完成封包排入 I/O 完成埠,而不需要啟動非同步 I/O 作業。 這適用于通知背景工作執行緒的外來事件,例如。

I/O 完成埠控制碼和與該特定 I/O 完成埠相關聯的每個檔案控制碼稱為 I/O 完成埠的參考。 當 I/O 完成埠沒有其他參考時,即會釋出。 因此,所有這些控制碼都必須正確關閉,才能釋放 I/O 完成埠及其相關聯的系統資源。 滿足這些條件之後,應用程式應該藉由呼叫 CloseHandle 函式來關閉 I/O 完成埠控制碼。

注意

I/O 完成埠與建立它的進程相關聯,而且無法在進程之間共用。 不過,在相同進程中的執行緒之間可共用單一控制碼。

 

執行緒和並行

要仔細考慮的 I/O 完成埠最重要的屬性是並行值。 當透過NumberOfConcurrentThreads參數建立完成埠時,會指定完成埠的並行值。 這個值會限制與完成埠相關聯的可執行執行緒數目。 當與完成埠相關聯的可執行執行緒總數達到並行值時,系統會封鎖與該完成埠相關聯的任何後續執行緒執行,直到可執行執行緒數目低於並行值為止。

在佇列中等候完成封包時,會發生最有效率的情況,但無法滿足等候,因為埠已達到其並行限制。 請考慮在 GetQueuedCompletionStatus 函式呼叫中等候的一個和多個執行緒並行值會發生什麼事。 在此情況下,如果佇列一律有完成封包等候,當執行中的執行緒呼叫 GetQueuedCompletionStatus時,不會封鎖執行,因為如先前所述,執行緒佇列是 LIFO。 相反地,此執行緒會立即挑選下一個佇列完成封包。 不會發生執行緒內容切換,因為執行中的執行緒會持續挑選完成封包,而其他執行緒無法執行。

注意

在上一個範例中,額外的執行緒似乎無用且永遠不會執行,但假設執行中的執行緒永遠不會由某些其他機制、終止或關閉其相關聯的 I/O 完成埠進入等候狀態。 設計應用程式時,請考慮所有這類執行緒執行影響。

 

要為並行值挑選的最佳整體最大值是電腦上的 CPU 數目。 如果您的交易需要冗長的計算,較大的並行值將允許更多執行緒執行。 每個完成封包可能需要較長的時間才能完成,但將會同時處理更多完成封包。 您可以搭配分析工具來實驗並行值,以達到應用程式的最佳效果。

如果與相同 I/O 完成埠相關聯的另一個執行執行緒因其他原因而進入等候狀態, GetQueuedCompletionStatus 中的執行緒也會處理完成封包,例如 SuspendThread 函式。 當處於等候狀態的執行緒再次開始執行時,當作用中線程數目超過並行值時,可能會有一段短暫的期間。 不過,系統在作用中線程數目低於並行值之前,不允許任何新的作用中線程,以快速減少此數目。 這是讓應用程式在其執行緒集區中建立比並行值更多的執行緒的原因之一。 執行緒集區管理超出本主題的範圍,但良好的經驗規則是至少線上程集區中有兩倍的執行緒,因為系統上有處理器。 如需執行緒共用的其他資訊,請參閱 執行緒集區

支援的 I/O 函式

下列函式可用來啟動使用 I/O 完成埠完成的 I/O 作業。 您必須透過呼叫CreateIoCompletionPort) 來啟用 I/O 完成埠機制,傳遞重迭結構的實例和先前與 I/O 完成埠相關聯的檔案控制代碼 (:

關於處理序和執行緒

BindIoCompletionCallback

CreateIoCompletionPort

GetQueuedCompletionStatus

GetQueuedCompletionStatusEx

PostQueuedCompletionStatus