PHP多进程之pcntl扩展的使用

PHP实现多进程的模块是pcntl,而且只有在linux下才使用这个拓展,不过现在服务器都基本使用linux,我们还是可以用起来的。

安装

可以直接使用pecl install pcntl,或者去https://pecl.php.net/下载源码包手动编译安装。

使用

先举个官方的栗子:

<?php

$pid = pcntl_fork();
//父进程和子进程都会执行下面代码
if ($pid == -1) {
    //错误处理:创建子进程失败时返回-1.
     die('could not fork');
} else if ($pid) {
     //父进程会得到子进程号,所以这里是父进程执行的逻辑
     pcntl_wait($status); //等待子进程中断,防止子进程成为僵尸进程。
} else {
     //子进程得到的$pid为0, 所以这里是子进程执行的逻辑。
}

使用到的函数:

  • pcntl_fork在当前进程当前位置产生分支(子进程)。fork是创建了一个子进程,父进程和子进程 都从fork的位置开始向下继续执行,不同的是父进程执行过程中,得到的fork返回值为子进程 号,而子进程得到的是0。

  • pcntl_wait 等待或返回fork的子进程状态。这个函数会挂起当前进程的执行直到一个子进程退出或接收到一个信号要求中断当前进程或调用一个信号处理函数。如果一个子进程在调用此函数时已经退出(俗称僵尸进程),此函数立刻返回。子进程使用的所有系统资源将被释放。

再来个经典栗子:

<?php
$children = []; //定义一个数组用来存储子进程的pid
$m = 10;    //fork 10次
for ($x = 0; $x < $m; $x++) {
    $pid = pcntl_fork();
    if ($pid == -1) {
        die('could not fork '.$x);
    } else if ($pid) {    //父进程执行的代码块
        $children[] = $pid;
        printf("Parent get child %d 's pid: %d\n", $x, $pid);
    } else {    //子进程执行的代码块
        $my_pid = posix_getpid();    //子进程获取自己的pid
        //子进程得到的$pid为0, 所以这里是子进程执行的逻辑。
        echo "Child $my_pid running...\n";
        sleep(10);        //子进程干点啥 这里是睡10秒
        
        echo "...Child $my_pid done\n";
        exit(0);        //子进程执行结束exit
    }
}

while(count($children) > 0) {
    foreach($children as $key => $pid) {
        $res = pcntl_waitpid($pid, $status, WNOHANG);    //获取返回指定pid的返回状态加了第二个参数非阻塞
        if($res == -1 || $res > 0){
            echo "Parent get child $pid 's status: $status\n";
            unset($children[$key]);
        }
    }
    sleep(1);        //每一秒去轮询没有退出的子进程状态
}

—- 最后更新于 2019-03-27 19:04:55

评论