前言
如果一个PHP脚本要处理10个任务,每个任务需要耗时1分钟,使用默认的单进程处理的话,需要耗时10分钟;但如果改成多进程的话,将这10个任务分配给10个进程处理,每个进程处理其中一个任务,则总耗时只需要1分钟,大大提高了效率。下面介绍如何使用PHP的pcntl
扩展来创建多进程。
代码
<?php
$parentPid = getmypid(); // 父进程ID
$childNum = 3; // 要创建的子进程数量
echo "父进程[$parentPid]准备fork $childNum 个子进程\n";
for ($i = 0; $i < $childNum; $i++) {
$ret = pcntl_fork();
switch ($ret) {
case -1:
echo "Fork子进程[$i]失败\n";
break;
case 0: // 子进程要处理的逻辑
$childPid = getmypid();
echo "子进程[$i]已创建, pid = $childPid\n";
sleep(60); // 使用sleep模拟任务执行
echo "子进程[$i]已结束, pid = $childPid\n";
exit();
default: // 父进程要处理的逻辑,不管它,直接break
break;
}
}
/*
* 循环等待所有的子进程退出
* 当pcntl_wait函数的返回值等于0的时候,说明所有的子进程已经退出
*/
while (($pid = pcntl_wait($status)) > 0) {
echo "子进程[$pid]已退出, status = $status\n";
}
echo "父进程已结束\n";
孤儿进程与僵尸进程
拥有父子进程的程序,如果处理不得当,就有可能会产生孤儿进程和僵尸进程,先看下他们的定义:
名词 | 定义 |
---|---|
孤儿进程 | 父进程已退出,而它的一个或多个子进程还在运行,那么这些子进程将成为孤儿进程。孤儿进程会被系统的init进程 (pid=1)收养,init进程 会成为这些子进程的新父进程。 |
僵尸进程 | 子进程退出后,如果父进程还在运行,但父进程没有调用wait() 或waitpid() ,那么该子进程将无法被父进程回收,从而成为僵尸进程。僵尸进程只能等到其父进程退出后由系统的init进程 回收。 |
孤儿进程一般没有什么危害,因为孤儿进程退出后,init进程
会回收它的相关资源。
但僵尸进程在其父进程不退出的情况下,会一直占用进程ID以及相关资源,无法释放,应尽量避免,因此在上面的PHP代码中,父进程循环调用pcntl_wait
函数等到所有的子进程退出,从而避免孤儿进程和僵尸进程产生。