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