epoll 和 select 的區別

   面試linux的時候,很多面試官都會問的一個問題是epoll和select的區別,而我總是答的不夠完整,今天總結一下epoll和select的區別。

   首先select是posix支持的,而epoll是linux特定的系統調用,因此,epoll的可移植性就沒有select好,但是考慮到epoll和select一般用作服務器的比較多,而服務器中大多又是linux,所以這個可移植性的影響應該不會很大。

   其次,select可以監聽的文件描述符有限,最大值爲1024,而epoll可以監聽的文件描述符則是系統對整個進程限制的最大文件描述符。

   接下來就要談epoll和select的性能 比較了,這個一般情況下應該是epoll表現好一些,否則linux也不會去特定實現epoll函數了,那麼epoll爲什麼比select更高效呢?原因有很多,第一點,epoll通過每次有就緒事件時都將其插入到一個就緒隊列中,使得epoll_wait的返回結果中只存儲了已經就緒的事件,而select則返回了所有被監聽的事件,事件是否就緒需要應用程序去檢測,那麼如果已被監聽但未就緒的事件較多的話,對性能的影響就比較大了。第二點,每一次調用select獲得就緒事件時都要將需要監聽的事件重複傳遞給操作系統內核,而epoll對監聽文件描述符的處理則和獲得就緒事件的調用分開,這樣獲得就緒事件的調用epoll_wait就不需要重新傳遞需要監聽的事件列表,這種重複的傳遞需要監聽的事件也是性能低下的原因之一。除此之外,epoll的實現中使用了mmap調用使得內核空間和用戶空間共享內存,從而避免了過多的內核和用戶空間的切換引起的開銷。

   然後就是epoll提供了兩種工作模式,一種是水平觸發模式,這種模式和select的觸發方式是一樣的,即只要文件描述符的緩衝區中有數據,就永遠通知用戶這個描述符是可讀的,這種模式對block和noblock的描述符都支持,編程的難度也比較小 ; 而另一種更高效且只有epoll提供的模式是邊緣觸發模式,只支持nonblock的文件描述符,他只有在文件描述符有新的監聽事件發生的時候(例如有新的數據包到達)纔會通知應用程序,在沒有新的監聽時間發生時,即使緩衝區有數據(即上一次沒有讀完,或者甚至沒有讀),epoll也不會繼續通知應用程序,使用這種模式一般要求應用程序收到文件描述符讀就緒通知時,要一直讀數據直到收到EWOULDBLOCK/EAGAIN錯誤,使用邊緣觸發就必須即將緩衝區中的內容讀完,否則有可能引起死等,尤其是當一個listen_fd需要監聽到達連接的時候,如果多個連接同時到達,如果每次只是調用accept一次,就會導致多個連接在內核緩衝區中滯留,處理的辦法是用while循環抱住accept,直到其出現EAGAIN。這種模式雖然容易出錯,但是性能要比前面的模式更高效,因爲只需要監聽是否有事件發生,發生了就直接將描述符加入就緒隊列即可。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章