PHP 多进程(fork)
背景
近期接触到一个项目,里面用到php脚本,脚本里使用并发处理数据,运行时发现内存超限,定位到时并发开太多进程,导致内存拷贝,触发内存超限。然后就想改进处理逻辑,控制并发量或者解决内存拷贝问题,因时间紧急,所以选择控制并发量,先把脚本跑起来,但之前接触php并发场景较少,一时无从下手,特此记录php并发控制的小示例。
函数说明
后续示例会用到两个进程并发相关的函数:pcntl_fork、pcntl_wait
pcntl_fork
官方文档:https://www.php.net/manual/zh/function.pcntl-fork.php
在当前进程当前位置产生分支(子进程)。译注:fork是创建了一个子进程,父进程和子进程都从fork的位置开始向下继续执行,不同的是父进程执行过程中,得到的fork返回值为子进程 号,而子进程得到的是0,fork返回值为-1表示开启失败。
pcntl_wait
官方文档:https://www.php.net/manual/zh/function.pcntl-wait.php
示例代码
<?php
const TASK_NUM = 10; // 任务数
const MAX_PROCESS = 3; // 最大进程数量,并发控制
$running = 0; // 记录正在运行的子进程数
for ($i = 0; $i < TASK_NUM; $i++) {
$pid = pcntl_fork(); // 开启新进程
if ($pid == -1) {
die("could not fork"); // 开启失败
} elseif ($pid) {
// 父进程逻辑
$running++; // 进程数+1
if ($running >= MAX_PROCESS) { // 子进程开启数量达到上限
pcntl_wait($status); // 等待有子进程退出
$running--; // 有子进程退出,进程数-1
}
} else {
// 子进程逻辑
$ss = rand(1, 20);
echo "child:$i, sleep $ss second... \n";
sleep($ss);
echo "child:$i, finish sleep.\n";
exit(0); // 子进程逻辑结束,注意退出点
}
}
// 等待所有子进程都结束
while ($running) {
pcntl_wait($status);
$running--;
}
echo "done.\n\n";
运行结果示例
wangyuanyuan14@B000000137984L php % php index.php
child:1, sleep 2 second...
child:0, sleep 20 second...
child:2, sleep 1 second...
child:2, finish sleep.
child:3, sleep 12 second...
child:1, finish sleep.
child:4, sleep 16 second...
child:3, finish sleep.
child:5, sleep 6 second...
child:4, finish sleep.
child:6, sleep 10 second...
child:5, finish sleep.
child:7, sleep 17 second...
child:0, finish sleep.
child:8, sleep 18 second...
child:6, finish sleep.
child:9, sleep 10 second...
child:7, finish sleep.
child:8, finish sleep.
child:9, finish sleep.
done.
wangyuanyuan14@B000000137984L php %