[原文地址:https://blog.ti-node.com/blog...]php
实际上php.net上是有event扩展的使用说明手册,可是呢,对于初学者来讲却并无什么卵用,由于没有太多的强有力使用案例代码,也没有给力的User Contributed Notes,因此可能形成的结果就是:根本就看不懂。node
这就是event文档,点击这里,大家能够感觉一下。从文档上看,event扩展一共实现了以下图几个基础类,其中最经常使用重要的就是Event和EventBase以及EventConfig三个类了,因此,先围绕这三位开展一下工做。socket
考虑到大家、我、还有正在看这个文章的其余未知物种,大多数可能并非搞C语言的老兵油子,因此我得用一些可能并不恰当的案例和比喻来尝试引入这些概念。函数
libevent中有五个字母是event,实际上就是说“event才是王道”。工具
Event类就是产生各类不一样类型事件的产出器,好比定时器事件、读写事件等等,为了提高民族荣誉感,咱们将这些各类事件比做各类战斗机:好比歼十、歼15和歼20。oop
EventBase类就相对容易介入了,这玩意显然就是一个航空母舰了,为了提高民族荣誉感,咱们就把EventBase类看成是辽宁舰。各类Event都必须依靠EventBase才能混口饭吃,这和战斗机有辽宁舰才有底气飞的更高更远是一个道理。必定是先有航母(EventBase),其次是战斗机(Event)挂在航母(EventBase)上。性能
EventConfig则是一个配置类,实例化后的对象做为参数能够传递给EventBase类,这样在初始化EventBase类的时候会根据这个配置初始化出不一样的EventBase实例。类比的话,这个类则有点儿相似于辽宁舰的舰岛,能够配置指挥整个辽宁舰。航空母舰的发展趋势是不须要舰岛的,一样,在实例化EventBase类时候一样也能够不传入EventConfig对象,直接进行实例化也是没有问题的。ui
下面咱们从开始写一个php定时器来步入到代码的节奏中。定时器是你们经常使用的一个工具,通常phper一说定时器,脑海中第一个想起的绝逼是Linux中的crontab。难道phper们离开了crontab真的就无法混了吗?是的,真的好羞耻,现实告诉咱们就是这样的,他们离开了crontab真的就无法混了。那么,是时候经过纯php来搞一波儿定时器实现了!spa
注意是真的纯php,连Event扩展都不用的那种。.net
<?php // 给当前php进程安装一个alarm信号处理器 // 当进程收到alarm时钟信号后会做出动做 pcntl_signal( SIGALRM, function(){ echo "tick.".PHP_EOL; } ); // 定义一个时钟间隔时间,1秒钟吧 $tick = 1; while( true ){ // 当过了tick时间后,向进程发送一个alarm信号 pcntl_alarm( $tick ); // 分发信号,呼唤起安装好的各类信号处理器 pcntl_signal_dispatch(); // 睡个1秒钟,继续 sleep( $tick ); }
代码保存成timer.php,而后php timer.php运行下,若是不出问题应该能跑起来。可是吧,这个代码有一坨问题。
因此,为了解决以上问题,是时候操做一波儿Event扩展了!
<?php // 初始化一个EventConfig(舰岛),虽然是个仅用于演示的空配置 $eventConfig = new EventConfig(); // 根据EventConfig初始化一个EventBase(辽宁舰,根据舰岛配置下辽宁舰) $eventBase = new EventBase( $eventConfig ); // 初始化一个定时器event(歼15,而后放到辽宁舰机库中) $timer = new Event( $eventBase, -1, Event::TIMEOUT | Event::PERSIST, function(){ echo microtime( true )." : 歼15,滑跃,起飞!".PHP_EOL; } ); // tick间隔为0.05秒钟,咱们还能够改为0.5秒钟甚至0.001秒,也就是毫秒级定时器 $tick = 0.05; // 将定时器event添加(将歼15拖到甲板加上弹射器) $timer->add( $tick ); // eventBase进入loop状态(辽宁舰!走你!) $eventBase->loop();
将代码保存为tick.php,而后php tick.php执行一下,以下图所示:
这种定时器是持久的定时器(每隔X时间必定会执行一次),若是想要一次性的定时器(隔X时间后就会执行一次,执行事后不再执行了),那么将上述代码中的“Event::TIMEOUT | Event::PERSIST”修改成“Event::TIMEOUT”便可。
若是你有一些自定义用户数据传递给回调函数,能够利用new Event()的第五个参数,这五个参数能够给回调函数用,以下所示:
<?php $timer = new Event( $eventBase, -1, Event::TIMEOUT | Event::PERSIST, function() use( &$custom ){ //echo microtime( true )." : 歼15,滑跃,起飞!".PHP_EOL; print_r( $custom ); }, $custom = array( 'name' => 'woshishui', ) );
须要重点说明的是new Event()这行代码了,我把原型贴过来给你们看下:
public Event::__construct ( EventBase $base , mixed $fd , int $what , callable $cb [, mixed $arg = NULL ] )
经过以上的案例代码能够总结一下平常流程:
捋清楚了定时器代码,咱们尝试来解决一个信号的问题。好比咱们的进程是常驻内存的daemon,再接收到某个信号后就会做出相应的动做,好比收到term信号后进程就会退出、收到usr1信号就会执行reload等等。
<?php // 依然是照例行事,尽管暂时没什么实际意义上的配置 $eventConfig = new EventConfig(); // 初始化eventBase $eventBase = new EventBase( $eventConfig ); // 初始化event $event = new Event( $eventBase, SIGTERM, Event::SIGNAL, function(){ echo "signal term.".PHP_EOL; } ); // 挂起event对象 $event->add(); // 进入循环 echo "进入循环".PHP_EOL; $eventBase->loop();
将代码保存成tick.php,而后执行php tick.php,代码已经进入循环了,而后咱们打开另一个终端,输入ps aux|grep tick查看一个php进程的pid进程号,对这个进程发送term信号,以下图所示:
奇怪啊,从第一张图看到确实收到term信号了,可是很奇怪为何这个php进程退出了呢?是由于没有添加Event::PERSIST,修改以下代码以下:
<?php $event = new Event( $eventBase, SIGTERM, Event::SIGNAL | Event::PERSIST, function(){ echo "signal term.".PHP_EOL; } );
有些心眼多鸡贼的,IO多路复用的方法一共有三个select、poll和epoll(Mac下叫作kqueue),那么咱们当前的event扩展用的是哪一个方法呢?那么,再表演一波儿:
<?php // 查看当前系统平台支持的IO多路复用的方法都有哪些? $method = Event::getSupportedMethods(); print_r( $method ); // 查看当前用的方法是哪个? $eventBase = new EventBase(); echo "当前event的方法是:".$eventBase->getMethod().PHP_EOL; // 跑了许久龙套的config此次也得真的露露手脚了 $eventConfig = new EventConfig; // 避免使用方法kqueue $eventConfig->avoidMethod('kqueue'); // 利用config初始化event base $eventBase = new EventBase( $eventConfig ); echo "当前event的方法是:".$eventBase->getMethod().PHP_EOL;
将代码保存了,而后执行一下,能够看到结果以下图所示:
那么,还有一些更鸡贼的人继续发问,前面提到的边缘触发和水平触发,如何确认呢?既然都用上epoll或者kqueue了,就必定要用边缘触发。
<?php $base = new EventBase(); echo "特性:".PHP_EOL; $features = $base->getFeatures(); // 看不到这个判断条件的,请反思本身“位运算”相关欠缺 if( $features & EventConfig::FEATURE_ET ){ echo "边缘触发".PHP_EOL; } if( $features & EventConfig::FEATURE_O1 ){ echo "O1添加删除事件".PHP_EOL; } if( $features & EventConfig::FEATURE_FDS ){ echo "任意文件描述符,不光socket".PHP_EOL; }
运行结果以下图所示:
[原文地址:https://blog.ti-node.com/blog...]