forked from elarity/advanced-php
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
elarity
committed
Apr 30, 2018
1 parent
305506f
commit 7f43d88
Showing
1 changed file
with
80 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
正如标题所言,颤颤抖抖开篇epoll。颤颤抖抖的原因大概也就是以前几乎没有亲自“手刃”epoll的经验,仅仅靠epoll的理论知识骗吃骗喝骗人事哄小孩儿装高手,现如今,没有了大师兄的铁头功照顾,没有了六师弟的轻功水上漂背,没有了阿梅的太极功护身,不得不自己个儿当一次排头兵了。 | ||
|
||
#### **说到底,还是因为自己虚。** | ||
|
||
![](https://static.ti-node.com/6396286943289671681) | ||
|
||
先立个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个快递,阿梅照样四两拨千斤,太极功夫收快递,而你,只需要安静的练习大力金刚腿。 | ||
|
||
![](https://static.ti-node.com/6396284198600048640) | ||
|
||
剃光头前的阿梅,就是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加速内核态数据拷贝 | ||
|
||
除此之外,需要特殊指出的是,epll本身的两种模式: | ||
- 水平触发。这种方式下,如果监听到了有X个事件发生,那么内核态会将这些事件拷贝到用户态,但是可惜的是,如果用户只处理了其中一件,剩余的X-1件出于某种原因并没有理会,那么下次的时候,这些未处理完的X-1个事件依然会从内核态拷贝到用户态。这样做是有阴阳两面的,阳面是事件安全的不会发生丢失,阴面是对于性能来说是一种浪费。其实这个时候的epoll颇有些类似于poll的工作方式。 | ||
- 边缘触发。这种方式下,是鸡血版本的epoll,是释放自我的epoll,也是应该是正确的使用方式。这种情况下,如果发生了X个事件,然而你只处理了其中1个事件,那么剩余的X-1个事件就算“丢失”了。性能是上去了,与之俱来的就是可能的事件丢失。 | ||
|
||
那么,你以为是时候写代码演示epoll了,然而并不是,原因有两个: | ||
- 通过C语言可以直接操作epoll,但是,为了避免装逼失败,我决定不用C来演示(放到后面再深入的时候) | ||
- 如果说通过PHP来操作,我不得不提一件悲催的事情,***据我自己得到的经验告诉我*** 那就是PHP无法直接操控epoll,而是要通过操作libevent来搞定epoll。 | ||
|
||
那么,什么是Libevent呢?怎么听着好耳熟,不光耳熟,你看下下图,是不是还有点儿眼熟?没错,这的博客的前端页面就是抄的[Libevent官网](http://libevent.org/ "Libevent官网")的。 | ||
![](http://static.ti-node.com/6396306572812746753) | ||
|
||
我先从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扩展为例。 | ||
|
||
- 下载event 2.3.0的稳定版本,wget https://pecl.php.net/get/event-2.3.0.tgz | ||
-![](http://static.ti-node.com/6396312840944222209) | ||
|
||
- 解压tgz源码包,tar -zxvf event-2.3.0.tgz | ||
-![](http://static.ti-node.com/6396312844396134400) | ||
|
||
|
||
- cd event-2.3.0进入到主目录中,然后执行phpize,再执行./configure | ||
![](http://static.ti-node.com/6396312847160180737) | ||
|
||
|
||
- 执行make | ||
|
||
![](http://static.ti-node.com/6396312851614531584) | ||
|
||
|
||
- 执行make install安装 | ||
![](http://static.ti-node.com/6396312854005284864) | ||
|
||
|
||
- 配置php的cli环境配置文件,注意不是apache2,也不是fpm的,而是cli的php.ini,添加一句:extension = '/usr/lib/php/20151012/event.so',然后在终端中执行php -m看下,是不是有event呢? | ||
|
||
好了,今天到这里正式收官,下一篇继续嗑php和他的event扩展二三事! | ||
-------- |