本文實(shí)例講述了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 的消息隊(duì)列。
我們可以通過 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)行計(jì)算任務(wù)
$tmp = 0;
for ($i = $task['start']; $i $task['end']; $i++) {
$tmp += $i;
}
echo '子進(jìn)程 PID : ', $worker->pid, ' 計(jì)算 ', $task['start'], ' - ', $task['end'], ' 結(jié)果 : ', $tmp, PHP_EOL;
//往管道中寫入計(jì)算的結(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} 計(jì)算 {$task['start']} - {$task['end']} \n";
//子進(jìn)程把計(jì)算的結(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} 計(jì)算結(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";
}
});
三、使用消息隊(duì)列來完成進(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} 計(jì)算 {$task['start']} - {$task['end']} \n";
$worker->push($tmp);
$worker->exit();
}, false, false);
//使用消息隊(duì)列,作為進(jìn)程間的通信
//注意,消息隊(duì)列是共享的
$worker->useQueue();
$worker_process[$i] = $worker;
//啟動子進(jìn)程
$worker->start();
}
for ($i = 0; $i $worker_process_nums; $i++) {
//只需用一個子進(jìn)程發(fā)送消息即可,因?yàn)橄㈥?duì)列是共享的
$worker_process[0]->push(json_encode([
'start' => mt_rand(1, 10),
'end' => mt_rand(50, 100),
]));
}
//注意,這里要暫停,防止加入隊(duì)列的任務(wù),立刻被主進(jìn)程讀出來。
sleep(1);
for ($i = 0; $i $worker_process_nums; $i++) {
$result = $worker_process[0]->pop();
echo "計(jì)算結(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è)計(jì)入門教程》、《PHP數(shù)據(jù)結(jié)構(gòu)與算法教程》及《php程序設(shè)計(jì)算法總結(jié)》
希望本文所述對大家PHP程序設(shè)計(jì)有所幫助。
您可能感興趣的文章:- 淺談swoole的作用與原理
- 淺談Swoole并發(fā)編程的魅力
- 詳解PHP Swoole長連接常見問題
- 詳解PHP Swoole與TCP三次握手
- Swoole擴(kuò)展的6種模式深入詳解
- php中Swoole的熱更新實(shí)現(xiàn)代碼實(shí)例
- swoole鎖的機(jī)制代碼實(shí)例講解
- Swoole源碼中如何查詢Websocket的連接問題詳解
- 詳解Swoole跟傳統(tǒng)的web開發(fā)的區(qū)別