简介
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
来源: https://www.cnblogs.com/52fhy/p/8901815.html