PHP swoole的process模塊創(chuàng)建和使用子進(jìn)程操作示例
本文實例講述了PHP swoole的process模塊創(chuàng)建和使用子進(jìn)程操作。分享給大家供大家參考,具體如下:
swoole中為我們提供了一個進(jìn)程管理模塊 Process,替換PHP的 pcntl 擴(kuò)展,方便我們創(chuàng)建進(jìn)程,管理進(jìn)程,和進(jìn)程間的通信。
swoole提供了2種進(jìn)程間的通信:
1、基于 unix socket 的管道 pipe。
2、基于 sysvmsg 的消息隊列。
我們可以通過 new swoole_process() 快速的創(chuàng)建一個進(jìn)程,默認(rèn)會創(chuàng)建一個 SOCK_DGRAM 類型的管道,用于進(jìn)程間的通信,當(dāng)然可以設(shè)置成其他類型,也可以不創(chuàng)建。
一、通過同步阻塞管道進(jìn)行進(jìn)程間通信
<?php $worker_process_nums = 5; $worker_process = []; for ($i = 0; $i < $worker_process_nums; $i++) { //創(chuàng)建子進(jìn)程 //默認(rèn)為每個子進(jìn)程創(chuàng)建一個管道,如果不想創(chuàng)建設(shè)置$pipe_type參數(shù)為false //注意管道默認(rèn)是同步阻塞,半雙工,如果讀取不到數(shù)據(jù)就會阻塞 $worker = new swoole_process(function (swoole_process $worker) { //注意,如果主進(jìn)程中不寫數(shù)據(jù)write(),那么子進(jìn)程這里read()就會阻塞 $task = json_decode($worker->read(), true); //進(jìn)行計算任務(wù) $tmp = 0; for ($i = $task['start']; $i < $task['end']; $i++) { $tmp += $i; } echo '子進(jìn)程 PID : ', $worker->pid, ' 計算 ', $task['start'], ' - ', $task['end'], ' 結(jié)果 : ', $tmp, PHP_EOL; //往管道中寫入計算的結(jié)果 $worker->write($tmp); //子進(jìn)程退出 $worker->exit(); }); //保存子進(jìn)程 $worker_process[$i] = $worker; //啟動子進(jìn)程 $worker->start(); } //往每個子進(jìn)程管道中投遞任務(wù) for ($i = 0; $i < $worker_process_nums; $i++) { $worker_process[$i]->write(json_encode([ 'start' => mt_rand(1, 10), 'end' => mt_rand(50, 100), ])); } //父進(jìn)程監(jiān)聽子進(jìn)程退出信號,回收子進(jìn)程,防止出現(xiàn)僵尸進(jìn)程 swoole_process::signal(SIGCHLD, function ($sig) { //必須為false,非阻塞模式 while ($ret = swoole_process::wait(false)) { echo "子進(jìn)程 PID : {$ret['pid']} 退出\n"; } });
二、通過 swoole_event_add 將管道設(shè)為異步,來進(jìn)行通信
<?php $worker_process_nums = 5; $worker_process = []; for ($i = 0; $i < $worker_process_nums; $i++) { $worker = new swoole_process(function ($worker) { //在子進(jìn)程中給管道添加事件監(jiān)聽 //底層會自動將該管道設(shè)置為非阻塞模式 //參數(shù)二,是可讀事件回調(diào)函數(shù),表示管道可以讀了 swoole_event_add($worker->pipe, function ($pipe) use ($worker) { $task = json_decode($worker->read(), true); $tmp = 0; for ($i = $task['start']; $i < $task['end']; $i++) { $tmp += $i; } echo "子進(jìn)程 : {$worker->pid} 計算 {$task['start']} - {$task['end']} \n"; //子進(jìn)程把計算的結(jié)果,寫入管道 $worker->write($tmp); //注意,swoole_event_add與swoole_event_del要成對使用 swoole_event_del($worker->pipe); //退出子進(jìn)程 $worker->exit(); }); }); $worker_process[$i] = $worker; //啟動子進(jìn)程 $worker->start(); } for ($i = 0; $i < $worker_process_nums; $i++) { $worker = $worker_process[$i]; $worker->write(json_encode([ 'start' => mt_rand(1, 10), 'end' => mt_rand(50, 100), ])); //主進(jìn)程中,監(jiān)聽子進(jìn)程管道事件 swoole_event_add($worker->pipe, function ($pipe) use ($worker) { $result = $worker->read(); echo "子進(jìn)程 : {$worker->pid} 計算結(jié)果 {$result} \n"; swoole_event_del($worker->pipe); }); } //父進(jìn)程監(jiān)聽子進(jìn)程退出信號,回收子進(jìn)程,防止出現(xiàn)僵尸進(jìn)程 swoole_process::signal(SIGCHLD, function ($sig) { //必須為false,非阻塞模式 while ($ret = swoole_process::wait(false)) { echo "子進(jìn)程 PID : {$ret['pid']} 退出\n"; } });
三、使用消息隊列來完成進(jìn)程間通信
<?php $worker_process_nums = 5; $worker_process = []; for ($i = 0; $i < $worker_process_nums; $i++) { //注意,這里將參數(shù)$pipe_type設(shè)為false,表示不創(chuàng)建管道 $worker = new swoole_process(function ($worker) { $task = json_decode($worker->pop(), true); $tmp = 0; for ($i = $task['start']; $i < $task['end']; $i++) { $tmp += $i; } echo "子進(jìn)程 : {$worker->pid} 計算 {$task['start']} - {$task['end']} \n"; $worker->push($tmp); $worker->exit(); }, false, false); //使用消息隊列,作為進(jìn)程間的通信 //注意,消息隊列是共享的 $worker->useQueue(); $worker_process[$i] = $worker; //啟動子進(jìn)程 $worker->start(); } for ($i = 0; $i < $worker_process_nums; $i++) { //只需用一個子進(jìn)程發(fā)送消息即可,因為消息隊列是共享的 $worker_process[0]->push(json_encode([ 'start' => mt_rand(1, 10), 'end' => mt_rand(50, 100), ])); } //注意,這里要暫停,防止加入隊列的任務(wù),立刻被主進(jìn)程讀出來。 sleep(1); for ($i = 0; $i < $worker_process_nums; $i++) { $result = $worker_process[0]->pop(); echo "計算結(jié)果 : {$result} \n"; } //父進(jìn)程監(jiān)聽子進(jìn)程退出信號,回收子進(jìn)程,防止出現(xiàn)僵尸進(jìn)程 swoole_process::signal(SIGCHLD, function ($sig) { //必須為false,非阻塞模式 while ($ret = swoole_process::wait(false)) { echo "子進(jìn)程 PID : {$ret['pid']} 退出\n"; } });
四、進(jìn)程可以通過 signal 監(jiān)聽信號,和 alarm 設(shè)置定時器。
我們可以在父進(jìn)程上設(shè)置監(jiān)聽信號,當(dāng)子進(jìn)程退出時,重新掛起子進(jìn)程。
也可以設(shè)置定時器,通過 swoole_process::kill($pid, 0); 定時檢測進(jìn)程是否存活。
<?php //每隔1秒觸發(fā)SIGALAM信號 //注意,alarm不能和Timer同時使用 swoole_process::alarm(1000 * 1000, 0); swoole_process::signal(SIGALRM, function ($signo) { static $cnt = 0; $cnt++; echo "時鐘定時信號\n"; if ($cnt > 10) { //清除定時器 swoole_process::alarm(-1); } }); swoole_process::signal(SIGINT, function ($signo) { echo "我被ctrl+c了\n"; //退出主進(jìn)程,不然將一直無法正常退出 exit(0); });
更多關(guān)于PHP相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《PHP網(wǎng)絡(luò)編程技巧總結(jié)》、《php socket用法總結(jié)》、《php面向?qū)ο蟪绦蛟O(shè)計入門教程》、《PHP數(shù)據(jù)結(jié)構(gòu)與算法教程》及《php程序設(shè)計算法總結(jié)》
希望本文所述對大家PHP程序設(shè)計有所幫助。
相關(guān)文章
php中g(shù)et_object_vars()方法用法實例
這篇文章主要介紹了php中g(shù)et_object_vars()方法用法,實例分析了get_object_vars()方法獲取對象中屬性的使用技巧,需要的朋友可以參考下2015-02-02Nginx環(huán)境下PHP flush失效的解決方法
最近在工作中發(fā)現(xiàn)了一個問題,PHP的flush居然失效了,從網(wǎng)上找了一些資料,發(fā)現(xiàn)是Nginx的原因,所以這篇文章就給大家介紹了問題與解決辦法,有需要的朋友們下面來一起看看吧。2016-10-10php基于ob_start(ob_gzhandler)實現(xiàn)網(wǎng)頁壓縮功能的方法
這篇文章主要介紹了php基于ob_start('ob_gzhandler')實現(xiàn)網(wǎng)頁壓縮功能的方法,涉及php中ob_gzip、ob_start等函數(shù)操作緩沖區(qū)及內(nèi)容壓縮相關(guān)技巧,需要的朋友可以參考下2017-02-02PHP實現(xiàn)的鏈?zhǔn)疥犃薪Y(jié)構(gòu)示例
這篇文章主要介紹了PHP實現(xiàn)的鏈?zhǔn)疥犃薪Y(jié)構(gòu),結(jié)合具體實例形式分析了php鏈?zhǔn)疥犃械亩x及入隊、出隊、打印隊列等基本操作實現(xiàn)與使用方法,需要的朋友可以參考下2017-09-09PHP刪除二維數(shù)組中相同元素及數(shù)組重復(fù)值的方法示例
這篇文章主要介紹了PHP刪除二維數(shù)組中相同元素及數(shù)組重復(fù)值的方法,涉及php針對數(shù)組的遍歷、判斷、比較等相關(guān)操作技巧,需要的朋友可以參考下2017-05-05