1. 程式人生 > >swoole_proces實現多進程

swoole_proces實現多進程

效果 顯示 僵屍進程 sat who shel arr port htm

簡介

swoole_process 是swoole提供的進程管理模塊,用來替代PHP的pcntl擴展。

首先,確保安裝的swoole版本大於1.7.2:

$ php --ri swoole

swoole

swoole support => enabled
Version => 1.10.1

實例說明

本例裏待消費的是三個shell命令,會分別創建一個子進程來消費。消費的時候故意sleep了1秒,以便直觀看到效果。

process_t1.php

<?php

$start_time = microtime(TRUE);

$cmds = [
    "uname"
, "date", "whoami" ]; foreach ($cmds as $cmd) { $process = new swoole_process( "my_process", true); $process->start(); $process->write($cmd); //通過管道發數據到子進程 echo $rec = $process->read();//同步阻塞讀取管道數據 } //子進程 function my_process(swoole_process $worker
){ sleep(1);//故意暫停1s $cmd = $worker->read(); // $return = exec($cmd);//exec只會輸出命令執行結果的最後一行內容,且需要顯式打印輸出 ob_start(); passthru($cmd);//執行外部程序並且顯示未經處理的、原始輸出,會直接打印輸出。 $return = ob_get_clean(); if(!$return) $return = 'null'; $worker->write($return);//通過管道讀取並返回數據,也可以使用echo代替write
// echo exec($return); //通過管道讀取並返回數據 } //子進程結束必須要執行wait進行回收,否則子進程會變成僵屍進程 while($ret = swoole_process::wait()){// $ret 是個數組 code是進程退出狀態碼, $pid = $ret['pid']; echo PHP_EOL."Worker Exit, PID=" . $pid . PHP_EOL; } $end_time = microtime(TRUE); echo sprintf("use time:%.3f s\n", $end_time - $start_time);

命令行裏運行:

$ php process_t1.php  

Linux
Sat Apr 21 15:29:55 CST 2018
root

Worker Exit, PID=672

Worker Exit, PID=674

Worker Exit, PID=676
use time:3.080 s

大家會覺得很奇怪,為什麽開了三個子進程,還是用了3秒,應該是1秒左右才對呀。

原因是父進程讀取子進程返回的數據的時候,是同步阻塞讀取:

 echo $rec = $process->read();//同步阻塞讀取管道數據

導致的後果就是父進程依次等待每個進程處理完並返回了內容,才走下一次循環。

解決方案1:
使用swoole_event_add將管道加入到事件循環中,變為異步模式:

// echo $rec = $process->read();//同步阻塞讀取管道數據

//使用swoole_event_add將管道加入到事件循環中,變為異步模式
swoole_event_add($process->pipe, function($pipe) use($process) {
    echo $rec = $process->read();
    
    swoole_event_del($process->pipe);//socket處理完成後,從epoll事件中移除管道
});

執行結果:

Worker Exit, PID=686

Worker Exit, PID=687

Worker Exit, PID=688
use time:1.060 s
Linux
Sat Apr 21 15:37:14 CST 2018
root

大家會發現,use time數據並不是最後打印出來的。已經是異步的了。 實際執行時間1s左右。

解決方案2:
先不獲取子進程返回值,循環結束後統一返回:

foreach ($cmds as $cmd) {
    $process = new swoole_process( "my_process", true);

    $process->start();
    $process->write($cmd); //通過管道發數據到子進程

    $process_arr[] = $process;
}

foreach ($process_arr as $process){
    echo $rec = $process->read();
}

執行結果:

Linux
Sat Apr 21 15:52:24 CST 2018
root

Worker Exit, PID=694

Worker Exit, PID=693

Worker Exit, PID=695
use time:1.061 s

參考

1、Process
https://wiki.swoole.com/wiki/page/p-process.html
2、swoole_process->read
https://wiki.swoole.com/wiki/page/217.html

swoole_proces實現多進程