PHP 多进程处理任务
PHP多进程一般应用在PHP_CLI命令行中执行php脚本,不要在web访问时使用。
模块安装
php查看是否安装了多进程模块
# pcntl是process control的缩写
$ php -m | grep pcntl
fork进程
php多进程的库函数manual手册
pcntl_fork — 在当前进程当前位置产生分支(子进程),父进程执行过程中,得到的fork 返回值为子进程号,而子进程得到的是0。
基础代码demo
<?php
// xxx 其他fork前父进程代码
$pid = pcntl_fork();
// 父进程和子进程都会执行下面代码
if ($pid == -1) {
// 错误处理:创建子进程失败时返回-1.
die('could not fork');
} else if ($pid) { // 父进程会得到子进程号,这里是父进程执行的逻辑
// 等待子进程中断,防止子进程成为僵尸进程
pcntl_wait($status);
} else { //子进程得到的$pid为0, 这里是子进程执行的逻辑。
// 业务处理
}
实战例子
比如有一个10w行数据文件要处理,为了提高效率此时我们就可以考虑多进程方式处理,每个进程处理文件的一部分。
需要先平均分割这个大文件成多个小文件(比如可以让进程数和小文件的个数等同)。现在计划分4个进程处理,一个文件2.5万行。
sh命令 split可以做到(split的用法比较简单,可以man split查看下手册)。
# 按2.5w行拆分file.log 带文件名前缀
# -l是按照行分割,-d是分割后的文件名按照数字列举
$ split -l 25000 -d file.log prefix_name
<?php
shell_exec('split -l 25000 -d file.log prefix_name');
// 4个子进程处理任务,主进程来循环fork,子进程来处理任务
for ($i = 0; $i < 4; $i++){
$pid = pcntl_fork();
if ($pid == -1) {
die("could not fork");
} elseif ($pid) {
echo "I'm the Parent $i\n";
} else {// 子进程处理
$content = file_get_contents("prefix_name0".$i);
// 业务处理 begin
// 业务处理 end
exit; // 一定要注意退出子进程,否则pcntl_fork() 会被子进程再fork,带来处理上的影响。
}
}
// 等待子进程执行结束
while (pcntl_waitpid(0, $status) != -1) {
$status = pcntl_wexitstatus($status);
echo "Child $status completed\n";
}