設想乙個場景,有100
萬使用者同時與乙個程序保持著
tcp連線,而每一時刻只有幾十個或幾百個tcp連線是活躍的(接收到tcp
包)也就是說,在每一時刻程序只需要處理這
100萬連線中的一小部分連線,那麼,如何才能高效的處理這種場景那,程序是否在每次詢問作業系統收集有事件發生的tcp
連線時,把這
100萬個連線告訴作業系統,然後由作業系統找出其中有事件發生的幾百個連線呢?,實際上在linux2.4
版本以前,那時的
select
或者poll
事件驅動方式就是這樣做的(就是每次通過輪詢的方式從
100萬個連線中找出活躍連線)
這裡有個明顯的問題,即在某一時刻,程序收集有事件的連線時,其實這100
萬連線中的大部分都是沒有事件發生的,因此,如果每次收集事件時,都把這100
萬連線的套接字傳給作業系統,而由作業系統核心尋找這些連線上有沒有未處理的事件,將會是巨大的資源浪費,而select
和poll
就是這樣做的,因此他們最多只能處理幾千個併發連線,而epoll
不是這樣做的,
epoll
把原先的乙個
select
或者poll
呼叫分成了
3個部分,呼叫
epoll_create
建立乙個
epoll
物件,呼叫
epoll_ctl
向epoll
物件中新增這
100萬個連線的套接字,呼叫epoll_wait
收集發生事件的連線,這樣只需要在程序啟動時建立乙個epoll
物件,並在需要的時候向他刪除或新增連線就可以了,在實際收集事件中,epoll_wait
的效率會非常高,因為呼叫
epoll_wait
時並沒有向它傳遞這
100萬個連線,核心也不需要去遍歷全部的連線
epoll_create方法
當某一程序呼叫epoll_create
方法時,
linux
核心會建立乙個
eventpoll
結構體,這個結構體中有兩個成員與
epoll
struct eventpoll
所有新增到
epoll
中的事件,都會與裝置(網絡卡)驅動程式建立**關係,也就是說相應的事件發生時會呼叫這裡的**方法,這個**方法在核心中叫做
ep_poll_callback
,當被呼叫時會把事件放到
rdllist
雙向鍊錶中(正是這種**機制使不用輪詢就可以知道哪些連線有事件發生)
當呼叫epoll_wait
檢查是否有發生事件的連線時,只是檢查
eventpoll
物件中的
rdllist
雙向鍊錶是否有
epitem
元素而已,如果
rdllist
鍊錶不為空,則把這裡的事件複製到使用者態記憶體中,同時將事件數量返回給使用者,因此
epoll_wait
的效率非常高。
epoll_ctl在向
epoll
物件中新增,修改和刪除事件時,從
rbr紅黑樹中查詢事件也非常的快,也就是說
epoll
是非常高效的,可以輕易處理百萬的併發。
epoll 和 kqueue 的原理
源引 首先我們來定義流的概念,乙個流可以是檔案,socket,pipe等等可以進行i o操作的核心物件。不管是檔案,還是套接字,還是管道,我們都可以把他們看作流。之後我們來討論i o的操作,通過read,我們可以從流中讀入資料 通過write,我們可以往流寫入資料。現在假定乙個情形,我們需要從流中讀...
epoll用法詳解
epoll i o event notification facility 在linux的網路程式設計中,很長的時間都在使用select來做事件觸發。在linux新的核心中,有了一種替換它的機制,就是epoll。相比於select,epoll最大的好處在於它不會隨著監聽fd數目的增長而降低效率。因為...
epoll原理剖析
首先我們來定義流的概念,乙個流可以是檔案,socket,pipe等等可以進行i o操作的核心物件。不管是檔案,還是套接字,還是管道,我們都可以把他們看作流。之後我們來討論i o的操作,通過read,我們可以從流中讀入資料 通過write,我們可以往流寫入資料。現在假定乙個情形,我們需要從流中讀資料,...