Libevent 是一个用C语言编写的、轻量级的开源高性能I/O框架,支持多种 I/O 多路复用技术: epoll、 poll、 dev/poll、 select 和 kqueue 等;支持 I/O,定时器和信号等事件;注册事件优先级。PHP提供了对应的扩展 libevent、 Event 。
libevent扩展很久没有更新了,仅支持PHP5系列,PHP7虽然有网友fork了 libevent 扩展的源码进行更新兼容,但是稳定性不好,可能会出现段错误,所以PHP7最好使用 Event 扩展。
与libevent扩展不同的是,Event 扩展提供了面向对象的接口,且支持更多特性。
libevent扩展
libevent地址: http://pecl.php.net/package/libevent
libevent文档: http://docs.php.net/libevent
系统需要先安装 Libevent 库:
yum install libevent-dev
然后安装PHP扩展。
PHP5安装:
pecl install libevent-0.1.0
PHP7安装(不稳定):
git clone https://github.com/expressif/pecl-event-libevent.git
cd pecl-event-libevent
phpize
./configure
make && sudo make install
注:后面的代码示例均使用的php5.6
+ libevent-0.1.0
环境。
基本使用
下面的例子实现了一个单进程的TCP server,基于libevent实现I/O复用,达到高性能。
libevent_tcp_server.php
我们先运行代码:
$ php libevent_tcp_server.php
waiting client...
start run...
客户端使用telnet:
$ telnet 127.0.0.1 9201
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
hello server!
代码里面我加了很多注释,基本上能看明白。需要注意的是:
1、event_base
是全局的,只需要创建一次,后续都是event的设置和添加。
2、event_set
的回调函数有三个参数,分别是$fd
, $events
, $arg
。也就是 event_set 函数的$fd
, $events
, $arg
参数。arg 如果需要多个,可以为数组。fd参数实际是保存的客户端连接,是个resource。events参数支持下列这些常量:
EV_TIMEOUT
: 超时。利用事件可以实现定时器EV_READ
: 只要网络缓冲中还有数据,回调函数就会被触发EV_WRITE
: 只要塞给网络缓冲的数据被写完,回调函数就会被触发EV_SIGNAL
: POSIX信号量EV_PERSIST
: 不指定这个属性的话,回调函数被触发后事件会被删除EV_ET
: Edge-Trigger边缘触发
使用event_buffer
libevent还提供了event_buffer_
系列函数。手册里的解释是:Libevent在基础的API里提供了一层抽象层,使用 buffered event ,我们无序手动处理I/O。估计是对性能的提升。
示例:
libevent_buffer_tcp_server.php
注释我都写了,相比前一个例字,主要有3个地方不同:
1、ev_accept
里设置read事件全换成了待buffer的函数;
2、ev_read
回调接收参数为2个;
3、ev_read
回调里读取消息使用 event_buffer_read
,而不是fread。另外增加了ev_write
,ev_error
回调。
定时器
libevent提供了event_timer_*
系列函数,实现一次性定时器,精度微秒。
libevent_timer.php
5){
event_timer_del($args[1]); //删除定时器
}
}
$base = event_base_new();
$ev_timer = event_timer_new();
event_timer_set($ev_timer, 'ev_timer', [$TIME_INTVAL, $ev_timer]);
event_base_set($ev_timer, $base);
event_timer_add($ev_timer, $TIME_INTVAL);//单位微秒
event_base_loop($base);
上面的例子实现了每1秒执行一次回调函数。
使用event_*
系列函数也可以实现:
libevent_timer2.php
5){
event_timer_del($args[1]);
}
}
$base = event_base_new();
$event = event_new();
event_set($event, 0, EV_TIMEOUT, 'ev_timer', [$TIME_INTVAL, $event]);
event_base_set($event, $base);
event_add($event, $TIME_INTVAL);
event_base_loop($base);
可以看出,event_timer_*
系列函数是对event_*
系列函数EV_TIMEOUT
事件的包装。
总结
event_*
系列函数基本上可以分为上面三大类。还有几个函数没有提到,大家看手册就能了解。
(未完待续)
推荐
PHP进阶之路
内容概要:从亿级 PV 项目的架构梳理,到性能提升实战,然后在更大体系的系统下,构造并使用服务治理框架。最后不要拘泥于一门语言,使用 java 快速构建一套 api 服务。包含内容:
纯干货!讲师是阿里巴巴资深研发工程师周梦康,《深入 PHP 内核》作者之一。感兴趣的朋友可以点击试看!