[原文地址: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...]