在 PHP 中,多进程编程可以通过使用相关的函数和扩展来实现。多进程编程可以用于同时执行多个任务、并行处理大量数据、利用多核处理器等场景。

  1. pcntl_fork(): 创建一个子进程,并在父进程和子进程中返回不同的进程ID。子进程是父进程的一个拷贝,它们在不同的内存空间中运行。

    示例:

    $pid = pcntl_fork();
    if ($pid === -1) {
        // 创建子进程失败
        exit("Failed to fork");
    } elseif ($pid === 0) {
        // 子进程执行的代码
        echo "This is the child process.\n";
        exit();
    } else {
        // 父进程执行的代码
        echo "This is the parent process.\n";
        pcntl_wait($status); // 等待子进程结束
    }
    

    在上述示例中,通过 pcntl_fork() 创建了一个子进程。在父进程中,$pid 的值为子进程的进程ID,而在子进程中,$pid 的值为 0。父进程和子进程分别执行不同的代码。

  2. pcntl_wait(): 等待一个子进程的结束,并返回子进程的退出状态。

    示例:

    $pid = pcntl_fork();
    if ($pid === -1) {
        exit("Failed to fork");
    } elseif ($pid === 0) {
        echo "This is the child process.\n";
        sleep(2);
        exit(123);
    } else {
        echo "This is the parent process.\n";
        pcntl_wait($status); // 等待子进程结束
        if (pcntl_wifexited($status)) {
            $exitCode = pcntl_wexitstatus($status);
            echo "Child process exited with code: $exitCode\n";
        }
    }
    

    在上述示例中,子进程 sleep(2) 2秒后退出,并返回退出状态码 123。父进程使用 pcntl_wait() 等待子进程的结束,并通过 pcntl_wifexited()pcntl_wexitstatus() 函数获取子进程的退出状态。

  3. pcntl_waitpid:

    //子进程数组
    $childs = array();
    
    // Fork10个子进程
    for ($i = 0; $i < 10; $i++) {
        $pid = pcntl_fork();
        if ($pid == -1) {
            die('Could not fork');
        }
    
        if ($pid) {
            echo "parent \n";
            $childs[] = $pid;
        } else {
            // 子进程代码运行
            // 子进程id
            $id = posix_getpid();
            sleep(2);
            echo "pid:$id sleep $i quit", PHP_EOL;
            // 子进程需要exit,防止子进程也进入for循环
            exit();
        }
    }
    
    while (count($childs) > 0) {
        foreach ($childs as $key => $pid) {
            $res = pcntl_waitpid($pid, $status, WNOHANG);
            //-1代表error, 大于0代表子进程已退出,返回的是子进程的pid,非阻塞时0代表没取到退出子进程
            if ($res == -1 || $res > 0) {
                unset($childs[$key]);
            }
        }
        sleep(1);
    }
    
  4. pcntl_signal(): 安装信号处理器,用于处理异步信号。可以用于捕捉和处理进程接收到的信号,如终止信号(SIGTERM)和中断信号(SIGINT)等。

    示例:

    declare(ticks = 1); // 声明在每个 tick 调用信号处理器
    
    function signalHandler($signal) {
        echo "Received signal: $signal\n";
    }
    
    pcntl_signal(SIGTERM, "signalHandler");
    
    while (true) {
        // 执行进程的主要逻辑
        // ...
    }
    

在上述示例中,通过 pcntl_signal() 安装了一个

信号处理器,用于处理收到的终止信号(SIGTERM)。当进程接收到该信号时,将会调用指定的 signalHandler() 函数进行处理。

这些函数只是 PHP 多进程编程中的一小部分,还有其他函数和扩展可用于更复杂的多进程场景。

需要注意的是,多进程编程需要谨慎处理 资源共享进程间通信同步等问题,以确保进程之间的 正确交互数据一致性