php Swoole使用多进程

2021-10-02

多进程执行代码

主进程异常退出时,子进程会继续执行,完成所有任务后退出

use Swoole\Process;

for ($n = 1; $n <= 3; $n++) {
	// 实例化一个进程指定执行程序,回调参数为当前进程对象
    $process = new Process(function ($process) use ($n) {
        echo 'Child #' . $process->pid . " start and sleep {$n}s" . PHP_EOL;
        sleep($n);
        echo 'Child #' . $process->pid . ' exit' . PHP_EOL;
    });
    // 启动子进程,子进程会继承父进程的内存和文件句柄,子进程在启动时会清除从父进程继承的EventLoop、Signal、Timer
    // 执行fork系统调用,启动子进程。在Linux系统下创建一个进程需要数百微秒时间。
    $pid = $process->start();
    // 设置进程执行在那几个cpu上
    // $process->setAffinity(array());
    // 设置进程的优先级,值越小优先级越高(-20到20)
    // 修改优先级的类型
    //$whichs = [
    //	   PRIO_PROCESS	进程
    //	   PRIO_PGRP	进程组
    //	   PRIO_USER	用户进程
    //];
    //$process->setAffinity(PRIO_PROCESS, $priority);
    // 获取进程的优先级
    //$process->getPriority(PRIO_PROCESS);
}
for ($n = 3; $n--;) {
	// 回收结束运行的子进程,阻塞等待,子进程结束后如果父进程不回收子进程将变成僵尸进程,影响资源
	// 结果包含子进程的PID、退出状态码、被哪种信号KILL
    $status = Process::wait(true);
    echo "Recycled #{$status['pid']}, code={$status['code']}, signal={$status['signal']}" . PHP_EOL;
}
echo 'Parent #' . getmypid() . ' exit' . PHP_EOL;

多进程指定类的方法

$process = new Process(['My', 'abc']);
$pid = $process->start();
$status = Process::wait(true);
echo "Recycled #{$status['pid']}, code={$status['code']}, signal={$status['signal']}" . PHP_EOL;

多进程执行--指定回调内启用协程

可以直接在子进程的函数中使用协程 API

use Swoole\Process;
use function Swoole\Coroutine\run;

$process = new Process(function ($process) {
    var_dump('PID=' . $process->pid);
    for ($i = 1; $i < 5; $i++){
    	Swoole\Coroutine::sleep($i);
        echo $i . "\n";
    }
}, false, 1, true);
$process->start();

$status = Process::wait(true);
echo "Recycled #{$status['pid']}, code={$status['code']}, signal={$status['signal']}" . PHP_EOL;

父进程与子进程使用标准输入输出进行通信

子进程内输出内容将不是打印屏幕,而是写入到主进程管道。读取键盘输入将变为从管道中读取数据

use Swoole\Process;
use function Swoole\Coroutine\run;

$process = new Process(function ($process) {
    var_dump('PID=' . $process->pid);
    for ($i = 1; $i < 5; $i++){
            echo $i . "\n";
    }
}, true);
$process->start();

run(function() use($process) {
    /*
     将unixSocket导出为Coroutine\Socket对象,然后利用 Coroutine\socket 对象的方法进程间通讯
     多次调用此方法,返回的对象是同一个
     关闭导出的socket时不会影响进程原有的管道
     必须在协程容器中使用
    */
    $socket = $process->exportSocket();
    // 一次接收所有的打印输出
    echo "from children: " . $socket->recv() . "\n";
});
$status = Process::wait(true);
echo "Recycled #{$status['pid']}, code={$status['code']}, signal={$status['signal']}" . PHP_EOL;
{/if}