Swoole是有自己的一個進程管理模塊,用來替代PHP的pcntl擴展,需要注意Process進程在系統(tǒng)是非常昂貴的資源,創(chuàng)建進程消耗很大,另外創(chuàng)建的進程過多會導(dǎo)致進程切換開銷大幅上升。
為什么不使用pcntl
1.pcntl沒有提供進程間通信的功能
2.pcntl不支持重定向標準輸入和輸出
3.pcntl只提供了fork這樣原始的接口,容易使用錯誤
Swoole是怎么解決的
1.swoole_process提供了基于unixsock的進程間通信,使用很簡單只需調(diào)用write/read或者push/pop即可
2.swoole_process支持重定向標準輸入和輸出,在子進程內(nèi)echo不會打印屏幕,而是寫入管道,讀鍵盤輸入可以重定向為管道讀取數(shù)據(jù)
3.swoole_process提供了exec接口,創(chuàng)建的進程可以執(zhí)行其他程序,與原PHP父進程之間可以方便的通信
創(chuàng)建進程
函數(shù)原型:
Swoole\Process::__construct(callable $function, $redirect_stdin_stdout = false, $create_pipe = true)
如果我們打印$process
會發(fā)現(xiàn),每次創(chuàng)建一個進程后,就會隨之創(chuàng)建一個管道,主進程想和哪一個進程通信,就向那個進程的管道寫入/讀取數(shù)據(jù)。
管道有2個方法,分別來寫入數(shù)據(jù),和讀取數(shù)據(jù)。
- $process->write(‘?dāng)?shù)據(jù)’);#寫入數(shù)據(jù)
- $process->read()#讀取數(shù)據(jù)
管道通訊方式一:
$worker = [];
for ($i = 0; $i < 3; $i++) {
$process = new Swoole\Process(function ($process) {
var_dump('子進程:' . $process->read());
sleep(1);
$process->write('子進程數(shù)據(jù)');
echo PHP_EOL . posix_getpid() . PHP_EOL;
}, false, true);
$pid = $process->start();
$worker[$pid] = $process;//把相應(yīng)的進程放到同一個數(shù)組當(dāng)中
$process->write('主進程數(shù)據(jù)');
// var_dump($process->read());//同步阻塞
}
foreach ($worker as $w) {
var_dump('主進程:' . $w->read());
}
管道通訊方式二:
for ($i = 0; $i < 3; $i++) {
$process = new Swoole\Process(function ($process) {
var_dump('子進程:' . $process->read());
sleep(1);
$process->write('子進程數(shù)據(jù)');
echo PHP_EOL . posix_getpid() . PHP_EOL;
}, false, true);
$pid = $process->start();
$process->write('主進程數(shù)據(jù)');
// 異步監(jiān)聽管道中的數(shù)據(jù),讀事件監(jiān)聽,當(dāng)管道可讀時觸發(fā)
swoole_event_add($process->pipe, function ($pipe) use ($process) {
var_dump('主進程:' . $process->read());
});
// var_dump($process->read());//同步阻塞
}
消息隊列的通訊
消息隊列:
- 一系列保存在內(nèi)核中的消息鏈表
- 有一個 msgKey, 可以通過此訪問不同的消息隊列
- 有數(shù)據(jù)大小限制, 默認 8192
- 阻塞 vs 非阻塞: 阻塞模式下 pop()空消息隊列/push()滿消息隊列會阻塞, 非阻塞模式可以直接返回
swoole 中使用消息隊列:
- 通信模式: 默認為爭搶模式, 無法將消息投遞給指定子進程
- 新建消息隊列后, 主進程就可以使用
- 消息隊列不可和管道一起使用, 也無法使用 swoole event loop
步驟:
1.啟用消息隊列作為進程間通信:
bool swoole_process->useQueue(int $msgkey = 0, int $mode = 2);
2.投遞數(shù)據(jù)到消息隊列中:
bool swoole_process->push(string $data);
3.從隊列中提取數(shù)據(jù)
string swoole_process->pop(int $maxsize = 8192);
案例:
for ($i = 0; $i < 3; $i++) {
$process = new Swoole\Process(function ($process) {
var_dump('子進程:' . $process->pop());
// $process->push('hello 主進程');#推送到主進程
});
$process->useQueue(1, 2 | swoole_process::IPC_NOWAIT);//啟用消息隊列,爭搶模式,非阻塞,可能會被任意一個子進程接收到
$pid = $process->start();
$process->push('hello 子進程');#推送到子進程,不能當(dāng)做管道使用
// echo '主進程消息:' . $process->pop() . PHP_EOL;
}