完成埠與高效能伺服器程式開發

2021-06-01 07:01:38 字數 3618 閱讀 2503

完成埠

重疊io

執行緒池vc++

完成埠與高效能伺服器程式開發

email:kruglinski_at_gmail_dot_com

blog:kruglinski.blogchina.com

如果你已經理解上面的概念,就已經很接近io完成埠了,當然這只是很常規的重疊操作它已經非常高效,但如果再結合多執行緒對乙個file或是socket進行重疊io操作就會非常複雜,通常程式設計師很難把握這種複雜度.完成埠可以說就是為了充分發揮多執行緒和重疊io操作相結合的效能而設計的.很多人都說它複雜,其實如果你自己實現乙個多執行緒的對乙個file或是socket進行重疊io操作的程式(注意是多個執行緒對乙個handle或socket進行重疊io操作,而不是啟乙個執行緒對乙個handle進行重疊io操作)就會發現完成埠實際上簡化了多執行緒裡使用重疊io的複雜度,並且效能更高,效能高在哪?下面進行說明.

我們可能寫過這樣的服務端程式:

例3.主程式:

1.監聽乙個埠

2.等待連線

3.當有連線來時

4.啟乙個執行緒對這個客戶端進行處理

5.回到2

服務執行緒:

1.讀客戶端請求

2.如果客戶端不再有請求,執行6

3.處理請求

4.返回操作結果

5.回到1

6.退出執行緒

這是一種最簡單的網路伺服器模型,我們把它優化一下

例4.主程式:

1.開乙個執行緒池,裡面有機器能承受的最大執行緒數個執行緒,執行緒都處於掛起(suspend)狀態

1.監聽乙個埠

2.等待連線

3.當有連線來時

4.從執行緒池裡resume乙個執行緒對這個客戶端進行處理

5.回到2

服務執行緒與例3模型裡的相同,只是當執行緒處理完客戶端所有請求後,不是退出而是回到執行緒池,再次掛起讓出cpu時間,並等待為下乙個客戶機服務.當然在此期間執行緒會因為io操作(服務執行緒的第1,5操作,也許還有其它阻塞操作)掛起自己,但不會回到執行緒池,也就是說它一次只能為乙個客戶端服務.

這可能是你能想到的最高效的服務端模型了吧!它與第乙個服務端模型相比少了很多個使用者態到核心態的context switch,反映也更加快速,也許你可能覺得這很微不足道,這說明你缺少對大規模高效能伺服器程式(比如網遊服務端)的認識,如果你的服務端程式要對幾千萬個客戶端進行服務呢?這也是微軟windows nt開發組在nt 5以上的系統中新增執行緒池的原因.

思考一下什麼樣的模型可以讓乙個執行緒為多個客戶端服務呢!那就要跳出每來乙個連線啟執行緒為其服務的固定思維模式,我們把執行緒服務的最小單元分割為單獨的讀或寫操作(注意是讀或寫不是讀和寫),而不是乙個客戶端從連線到斷開期間的所有讀寫操作.每個執行緒都使用重疊io進行讀寫操作,投遞了讀寫請求後執行緒回到執行緒池,等待為其它客戶機服務,當操作完成或出錯時再回來處理操作結果,然後再回到執行緒池.

看看這樣的伺服器模型:

例5.主程式:

1.開乙個執行緒池,裡面有機器內cpu個數兩倍的執行緒,執行緒都處於掛起(suspend)狀態,它們在都等處理一次重疊io操作的完成結果

1.監聽乙個埠

2.等待連線

3.當有連線來時

4.投遞乙個重疊讀操作讀取命令

5.回到2

服務執行緒:

1.如果讀完成,則處理讀取的內容(如http get命令),否則執行3

2.投遞乙個重疊寫操作(如返回http get命令需要的網頁)

3.如果是乙個寫操作完成,可以再投遞乙個重疊讀操作,讀取客戶機的下乙個請求,或者是關閉連線(如http協議裡每發完乙個網頁就斷開)

4.取得下乙個重疊io操作結果,如果io操作沒有完成或沒有io操作則回到執行緒池

假設這是乙個web伺服器程式,可以看到工作者執行緒是以讀或寫為最小的工作單元執行的,在主程式裡面進行了一次重疊讀操作

當讀操作完成時乙個執行緒池中的乙個工作者執行緒被啟用取得了操作結果,處理get或post命令,然後傳送乙個網頁內容,傳送也是乙個重疊操作,然後處理對其它客戶機的io操作結果,如果沒有其它的東西需要處理時回到執行緒池等待.可以看到使用這種模型傳送和接收可以是也可以不是乙個執行緒.

當傳送操作完成時,執行緒池中的乙個工作者執行緒池啟用,它關閉連線(http協議),然後處理其它的io操作結果,如果沒有其它的東西需要處理時回到執行緒池等待.

看看在這樣的模型中乙個執行緒怎麼為多個客戶端服務,同樣是模擬乙個web伺服器例子:

假如現在系統中有兩個執行緒,threada,threadb它們在都等處理一次重疊io操作的完成結果

當乙個客戶機clienta連線來時主程式投遞乙個重疊讀操作,然後等待下乙個客戶機連線,當讀操作完成時threada被啟用,它收到乙個http get命令,然後threada使用重疊寫操作傳送乙個網頁給clienta,然後立即回到執行緒池等待處理下乙個io操作結果,這時傳送操作還沒有完成,又有乙個客戶機clientb連線來,主程式再投遞乙個重疊讀操作,當讀操作完成時threada(當然也可能是threadb)再次被啟用,它重複同樣步驟,收到乙個get命令,使用重疊寫操作傳送乙個網頁給clientb,這次它沒有來得及回到執行緒池時,又有乙個連線clientc連入,主程式再投遞乙個重疊讀操作,讀操作完成時threadb被啟用(因為threada還沒有回到執行緒池)它收到乙個http get命令,然後threadb使用重疊寫操作傳送乙個網頁給clientc,然後threadb回到執行緒池,這時threada也回到了執行緒池.

可以想象現在有三個掛起的傳送操作分別是threada傳送給clienta和clientb的網頁,以及threadb傳送給clientc的網頁,它們由作業系統核心來處理.threada和threadb現在已經回到執行緒池,可以繼續為其它任何客戶端服務.

當對clienta的重疊寫操作已經完成,threada(也可以是threadb)又被啟用它關閉與clienta連線,但還沒有回到執行緒池,與此同時傳送給clientb的重疊寫操作也完成,threadb被啟用(因為threada還沒有回到執行緒池)它關閉與clientb的連線,然後回到執行緒池,這時clientc的寫操作也完成,threadb再次被啟用(因為threada還是沒有回到執行緒池),它再關閉與clientc的連線,這時threada回到執行緒池,threadb也回到執行緒池.這時對三個客戶端的服務全部完成.可以看到在整個服務過程中,"建立連線","讀資料","寫資料"和"關閉連線"等操作是邏輯上連續而實際上分開的.

到現在為止兩個執行緒處理了三次讀操作和三次寫操作,在這些讀寫操作過程中所出現的狀態機(state machine)是比較複雜的,我們模擬的是經過我簡化過的,實際上的狀態要比這個還要複雜很多,然而這樣的服務端模型在客戶端請求越多時與前兩個模型相比的效能越高.而使用完成埠我們可以很容易實現這樣的伺服器模型.

微軟的iis web伺服器就是使用這樣的服務端模型,很多人說什麼阿帕奇伺服器比iis的效能好什麼什麼的我表示懷疑,除非阿帕奇伺服器可以將執行緒分割成,為更小的單元服務,我覺得不太可能!這種完成埠模型已經將單個讀或寫操作作為最小的服務單元,我覺得在相同機器配置的情況下iis的效能要遠遠高於其它web伺服器,這也是從實現機理上來分析的,如果出現效能上的差別可能是在不同的作業系統上,也許linux的核心比windows的要好,有人真的研究過嗎?還是大家一起在炒作啊.

希望大家不要陷在這個程式的框架中,ctrl+c,ctrl+v沒有什麼意義,要理解它的實質.程式使用visual c++ 6.0 sp5+2003 platform sdk編譯通過,在windows xp professional下調試執行通過.程式執行的最低要求是windows 2000作業系統.

完成埠與高效能伺服器程式開發

遊戲的開發中,完成埠是如此的重要,筆者實在沒有時間去寫文章介紹這種技術,也許將來我會公布 聊齋世界 中用到的 完成埠與高效能伺服器程式開發 波布e族 發表於 2006 10 13 8 31 00 此文 xfocus。早在兩年前我就已經能很熟練的運用完成埠以及執行緒池,基於這種模型的服務端程式應該是n...

完成埠與高效能伺服器程式開發

blog kruglinski.blogchina.com 如果你已經理解上面的概念,就已經很接近io完成埠了,當然這只是很常規的重疊操作它已經非常高效,但如果再結合多執行緒對乙個file或是socket進行重疊io操作就會非常複雜,通常程式設計師很難把握這種複雜度.完成埠可以說就是為了充分發揮多執...

Linux 高效能伺服器程式框架

伺服器解構主要分為如下三個主要模組 1 i o處理單元。接收客戶端傳送的資料都屬於i o處理單元。2 邏輯單元。接收到資料之後進行的一些處理都屬於邏輯單元。3 儲存單元。如下圖所示 伺服器程式設計框架 1 c s模型 c就是客戶端,s就是伺服器。所以這個模型也稱客戶端 伺服器模型。c s模型如下圖所...