Epoll是poll的改進版,更加高效,能同時處理大量文件描述符,跟高并發(fā)有關,Nginx就是充分利用了epoll的特性。講這些沒用,我們先了解poll是什么。
Poll本質上是Linux系統(tǒng)調(diào)用,其接口為int poll(struct pollfd *fds,nfds_t nfds, int timeout),作用是監(jiān)控資源是否可用。
舉個例子,一個Web服務器建了多個socket連接,它需要知道里面哪些連接傳輸發(fā)了請求需要處理,功能與select系統(tǒng)調(diào)用類似,不過poll不會清空文件描述符集合,因此檢測大量socket時更加高效。
我們重點看看epoll,它大幅提升了高并發(fā)服務器的資源使用率,相比poll而言哦。前面提到poll會輪詢整個文件描述符集合,而epoll可以做到只查詢被內(nèi)核IO事件喚醒的集合,當然它還提供邊沿觸發(fā)(Edge Triggered)等特性。
不知大家是否了解C10K問題,指的是服務器如何支持同時一萬個連接的問題。如果是一萬個連接就有至少一萬個文件描述符,poll的效率也隨文件描述符的更加而下降,epoll不存在這個問題是因為它僅關注活躍的socket。
這是怎么做到的呢?簡單來說epoll是基于文件描述符的callback函數(shù)來實現(xiàn)的,只有發(fā)生IO時間的socket會調(diào)用callback函數(shù),然后加入epoll的Ready隊列。更多實現(xiàn)細節(jié)可以參考Linux源碼,
無論是select、poll還是epoll,他們都要把文件描述符的消息送到用戶空間,這就存在內(nèi)核空間和用戶空間的內(nèi)存拷貝。其中epoll使用mmap來共享內(nèi)存,提高效率。
Mmap不是進程的概念,這里提一下是因為epoll使用了它,這是一種共享內(nèi)存的方法,而Go語言的設計宗旨是"不要通過共享來通信,通過通信來共享",所以我們也可以思考下進程的設計,是使用mmap還是Go提供的channel機制呢。