php实现epoll,PHP socket初探 --- 颤颤抖抖开篇libevent(一)
正如標題所言,顫顫抖抖開篇epoll。顫顫抖抖的原因大概也就是以前幾乎沒有親自“手刃”epoll的經驗,僅僅靠epoll的理論知識騙吃騙喝騙人事哄小孩兒裝高手,現如今,沒有了大師兄的鐵頭功照顧,沒有了六師弟的輕功水上漂背,沒有了阿梅的太極功護身,不得不自己個兒當一次排頭兵了。
說到底,還是因為自己虛。
先立個flag,那就是epoll比select牛逼,盡管select是POSIX標準。即便是select的高配版本poll,也比epoll差太多太多。網絡如此發達的今天,epoll是解決c10k問題的功臣,這是沒有辦法的事情。epoll雖然是后出生的,但是卻有著與生俱來的高傲,就像王思聰;select就是普通屌絲,花點兒錢使勁裝扮自己也頂多就是個poll。這poll和epoll,可差一個e呢,沒辦法,與生俱來的差距。
坊間傳聞,在epoll出世前,QQ用戶量劇增,但是select以及select的高配版本poll都無法解決他們的問題,于是乎QQ當年的服務器就不得不用UDP協議來避規這個問題,一直到后來有了epoll,QQ開始逐步在PC客戶端中的配置項中允許用戶選擇UDP服務器或TCP服務器。
還是通過淺顯的示例來說明下為啥epoll比select厲害(這個例子在前面文章中應該提過,今兒再回放一遍)。
你要去繼續練習大力金剛腿,阿梅還是要替你收雙十一的10個快遞。為了方便自己記憶這些快遞,你把十個快遞記錄到了一個清單上給了阿梅。但這個時候阿梅顯然不太清楚怎么應付這場景,于是每當收到X個快遞,阿梅都是直接把快遞清單抄寫一份再拿給你并告訴你:“有快遞來了!”,至于來了幾個快遞以及是分別是哪個鏢局護送的,阿梅是不會告訴你的。于是只能是你自己,把單子上的10個快遞逐次和收到的對比一遍,然后對比完畢后再把這個單子給了阿梅,然后阿梅繼續等。
又是一年雙十一,阿梅這次學聰明了,經歷過那場球賽后,她已經得到了自我,實現了人生價值,今年的阿梅是一個全新的阿梅,一個剃了光頭的阿梅。
你要去繼續練習大力金剛腿,阿梅還是要替你收雙十一的10個快遞。為了方便自己記憶這些快遞,你把十個快遞記錄到了一個清單上給了阿梅。但這個時候的阿梅顯然已經得到了自我,是升華了的阿梅,于是每收到X個( X >= 1 )快遞,阿梅都會在沖你喊一句:“順豐鏢局大師兄的鐵頭套,圓通鏢局六師弟的雞蛋到了!”,而你,不用再去依次對單子,阿梅會直接告訴你是哪個鏢局護送的哪個快遞,然后她還會按照你提前告訴她的“如果收到雞蛋就給六師弟,收到鐵頭套就給大師兄”。哪怕你買了10000個快遞,阿梅照樣四兩撥千斤,太極功夫收快遞,而你,只需要安靜的練習大力金剛腿。
剃光頭前的阿梅,就是select,不敢正眼看老板娘一眼。
剃光頭后的阿梅,就是epoll,可徒手接魔鬼隊的死亡之球。
快遞就相當于是socket fd,包括監聽socket和連接socket;那個清單就是fd的集合;阿梅就是select或者epoll;你就是當前的一個進程;某個快遞到了,就相當于是某個fd已經可讀或可寫。
select雖然一定程度上解決了一個進程可以讀寫多個fd的問題,但是select有如下致命缺點:
默認情況下,select可管理的fd的數量是1024個(阿梅最多幫你收1024個快遞)
select每次檢測到fd集合中有可讀寫的fd時,它會把整個fd全部復制一遍給你,然后你自己再去逐個輪詢究竟是哪個fd可讀寫
正如以上所說,它會把整個fd全部復制給你(她把整個清單抄了一份給你),從術語上講,這個過程是將fd從內核態復制一遍給用戶態的調用進程
正如以上所說,你自己逐個輪詢所有fd才能知道究竟是哪個可讀寫(反正就是有快遞來了,來了幾個都是誰你自己個兒對著清單查去)
你自己個輪詢的過程是線性的,如果有個n個fd,那么時間復雜度一定是O(n)
而epoll則擁有更加專業的高端大氣上檔次的技能指標:
理論上可以搞定無上限的fd(可以收無數個快遞的阿梅)
只挑出可讀寫(其實嚴格意義上還有異常)的活躍的fd,其余的fd不理會
使用MMAP加速內核態數據拷貝
除此之外,需要特殊指出的是,epoll本身的兩種模式:
水平觸發。這種方式下,如果監聽到了有X個事件發生,那么內核態會將這些事件拷貝到用戶態,但是可惜的是,如果用戶只處理了其中一件,剩余的X-1件出于某種原因并沒有理會,那么下次的時候,這些未處理完的X-1個事件依然會從內核態拷貝到用戶態。這樣做是有陰陽兩面的,陽面是事件安全的不會發生丟失,陰面是對于性能來說是一種浪費。其實這個時候的epoll頗有些類似于poll的工作方式。
邊緣觸發。這種方式下,是雞血版本的epoll,是釋放自我的epoll,也是應該是正確的使用方式。這種情況下,如果發生了X個事件,然而你只處理了其中1個事件,那么剩余的X-1個事件就算“丟失”了。性能是上去了,與之俱來的就是可能的事件丟失。
那么,你以為是時候寫代碼演示epoll了,然而并不是,原因有兩個:
通過C語言可以直接操作epoll,但是,為了避免裝逼失敗,我決定不用C來演示(放到后面再深入的時候)
如果說通過PHP來操作,我不得不提一件悲催的事情,據我自己得到的經驗告訴我 那就是PHP無法直接操控epoll,而是要通過操作libevent來搞定epoll。
那么,什么是Libevent呢?怎么聽著好耳熟,不光耳熟,你看下下圖,是不是還有點兒眼熟?沒錯,這的博客的前端頁面就是抄的Libevent官網的。
我先從Libevent官網抄襲一段話:“Currently, libevent supports /dev/poll, kqueue(2), event ports, POSIX select(2), Windows select(), poll(2), and epoll(4). ”,你就能大概知道Libevent是干啥的了。大概意思就是Libevent對/dev/poll、Mac中的kqueue、select、poll以及epoll的API進行了封裝,屏蔽了這幾個多路復用開發上的一些細節和不同點,對外提供統一的API的一個高性能網絡事件庫。
額外提醒一點,這個東西是用C語言編寫的,幾十年過去了,你大爺還是你大爺。
回到正路上來,就是“PHP中如何使用Libevent”。在pecl.php.net上,有兩個擴展都可以使phper方便地操控libevent,一個就叫libevent,另一個叫做event,推薦大家用后者。前者不知道什么原因版本一直停留在0.10 Beta狀態,開發日期則停留在了2013-05-22日,我沒怎么試過,估計可能不支持php7,不過,還是要感謝開發者。event擴展就比較屌了,版本迭代不錯,看起來開發者挺積極的,也支持php7,目前的穩定版本是2.3.0,所以推薦大家使用event擴展。
正好在此補充一下php擴展的安裝方式,以event擴展為例。
解壓tgz源碼包,tar -zxvf event-2.3.0.tgz
cd event-2.3.0進入到主目錄中,然后執行phpize,再執行./configure
執行make
執行make install安裝
配置php的cli環境配置文件,注意不是apache2,也不是fpm的,而是cli的php.ini,添加一句:extension = '/usr/lib/php/20151012/event.so',然后在終端中執行php -m看下,是不是有event呢?
好了,今天到這里正式收官,下一篇繼續嗑php和他的event擴展二三事!
總結
以上是生活随笔為你收集整理的php实现epoll,PHP socket初探 --- 颤颤抖抖开篇libevent(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大端和小端C++转载记录
- 下一篇: mysql 查询部门中男女人数,工资最高