跳到主要内容

PHP多进程编程

多进程编写

pcntl_fork函数来创建一个子进程,系统调用的是使用clone函数来创建的。

问题

使用多进程开发,必须清除的几件事:

  1. 到底创建了几个进程
  2. 每个进程$count是多少
  3. 每个进程到底从哪个地方开始运行代码
  4. fork之后,每个进程的变量$i, $count的值到底是多少
  5. 每个进程运行到哪一行语句结束
<?php

$count = 10;
for ($i = 0; $i < 2; $i++) {
$pid = pcntl_fork();
if ($pid == 0) {
$count += 1;
} else {
$count *= 10;
}
}

fprintf(STDOUT, "poid=%d, count=%d\n", posix_getpid(), $count);

运行结果

[root@jb51 process]# php demo11.php
poid=5677, count=1000
poid=5683, count=110
poid=5684, count=101
[root@jb51 process]# poid=5685, count=12

感觉是不是和预想的一些值有出处。

分析
  1. 开始运行:php demo11.php
  2. for循环开始
  3. 遇到fork函数之后,创建了一个子进程,假设命名这个子进程为child1,变量$i = 0目前为0,$count = 10,子进程child1继续执行,这个时候满足$pid == 0,进行$count += 1,此时$count = 11$i++之后变成1。
  4. CPU现在要调度到父进程,执行$count *= 10,此时$count = 100$i++之后变为1
  5. 假设父进程还在继续运行,$count=100了,$i=1了,再次执行fork,又产了一个子进程,命名为child2;假设CPU还是在调度父进程,$count = 1000,$i = 2,正好for循环退出,父进程的最终结果是:$count = 1000
  6. CPU运行child2子进程,执行$count += 1,那么$count = 101,$i = 2child2的子进程最终结果是:$count = 101
  7. CPU又调度到child1子进程,此时变量$count = 11,$i = 1,这个时候child1执行pcntl_fork函数,产生的子进程名称为child3,此时$i=1,$count = 11,会复制数据,child1继续执行,肯定是满足child1是child3的父亲,也算是一个父进程,会走else,此时$count = 11 * 10 = 110,此时$i = 2了,此时child1的最终结果:$count = 110
  8. CPU又调度到child3子进程,因为会复制数据,基础数据:$count = 11,$i = 1,最终结果为:$count = 12

关系

  • child1child2是兄弟进程,父进程是当前的主进程
  • child3的父亲是child1

我们可以加上一个死循环来阻塞一下,看看进程树

<?php

$count = 10;
for ($i = 0; $i < 2; $i++) {
$pid = pcntl_fork();
if ($pid == 0) {
$count += 1;
} else {
$count *= 10;
}
}

while (1) {
fprintf(STDOUT, "poid=%d, count=%d\n", posix_getpid(), $count);
sleep(10);
}

运行结果

这样可以很清楚的看到几个进程之间的关系。

稍作修改,加上一个break之后又是什么情况

<?php

$count = 10;
for ($i = 0; $i < 2; $i++) {
$pid = pcntl_fork();
if ($pid == 0) {
$count += 1;
} else {
$count *= 10;
break;
}
}

fprintf(STDOUT, "poid=%d, count=%d\n", posix_getpid(), $count);
分析
  1. CPU调度主进程,执行fork之后,就产生了一个子进程,命名为child1,并且复制父进程的代码段,即此时:$i = 0, $count =10
  2. 假设CPU继续执行主进程,必然会满足else分支,此时$count = 100,$i = 1,这个时候遇到break退出了for循环,主进程就结束了,主进程的最终结果:$count = 100
  3. CPU调度到child1子进程,执行if分支,$count = 11, $i = 1,还是小于2,会继续执行该进程,必然会执行pcntl_fork函数,又创建了有一个子进程,命名为child2,复制数据$count = 11, $i = 1
  4. 假设CPU还是继续调度child1进程,此时它已经是一个父亲了,此时满足else分支 ,$count = 110,遇到break退出,child1进程的最终结果:$count = 110
  5. CPU切换调度到child2子进程,$count = 11, $i = 1,满足if分支,此时$count = 12, $i = 2,退出循环

进程关系:

  • child1子进程的父亲是主进程
  • child2子进程的父亲是child1

进程树

进程结果