I/O Completion Port

I/O Completion Port 最主要用在 server application 上,可以讓 server threads 減少 context switch,擁有最大的效率。它的工作方大概是這樣:

server 首先產生一個 file handle(比如說 socket。注意此 file handle 必需支援 overlapped I/O,也就是非同步 I/O),接著呼叫 CreateIoCompletionPort 產生一個 completion port 並將剛剛產生的 file handle associate 給它。

Server threads 透過 GetQueuedCompletionStatus 來取得 completion packet。這個 completion packet 是當 client 對 server 有 reqeust 時候就會產生。GetQueuedCompletionStatus 如果抓不到 packet,該 thread 就會被 block。如果抓到 packet,則該 thread 就會變為 active,負責處理 client request。

Thread 放在 thread pool,它們的順序是 LIFO,後進先出。意思就是說,當有 client request 進來時,最後進 pool 的 thread 會負責處理。這樣的好處可以減少 context switch。假設每個 client request 都是在前一個處理完後才進來,那麼負責處理的 thread 就永遠是同一個。等於就沒有 context switch。

這邊有一個 concurrency 值,代表同時間能有幾個 active thread 來處理 client request(或稱接收 completion packet)。concurrency 值等於 1 的話,代表同時間只能處理 1 個 completion packet。在處理前一個 packet 時,第 2 個 packet 會被 block 住。

假設目前有 2 個 client request 進來。concurrency 值為 1。thread1 會負責處理 packet1,但如果 thread1 需要等待某些 I/O,此時 thread1 會變為 inactive,Windows 會 context switch 到 thread2(此時 thread2 變為 active,負責處理 packet2),避免浪費掉 thread1 等待的時間。

但有時候 server 目前的 concurrency 值會大於限制值。想像以下情況:completion port 中有好幾個 packet。當 thread1 成為 active,負責處理 packet1,因為某種原因被 block 住(可能是等待 disk 回應或其它因素),此時 thread1 變為 inactive,原本被 block 住的 thread2 會被釋放變為 active,負責處理 packet2。在此電光火石之間,block thread1 的原因消失了(I/O 完成),thread1 也變成 active。如此同時間就有 2 個 active thread。

原則上來說,concurrency 值大概不是等於限制值,就是大於限制值 1。

Server threads 也可以透過 PostQueuedCompletionStatus 將 completion packet 放進 completion port 中。這可以用做 thread 之間通訊用,或者 server process 用來通知所有 thread 某些事件(例如:server shutdown)。


留言

熱門文章