php的多进程实验分析

pcntl_fork — 在当前进程当前位置产生分支(子进程)。译注:fork是创建了一个子进程,父进程和子进程 都从fork的位置开始向下继续执行,不同的是父进程执行过程中,得到的fork返回值为子进程 号,而子进程得到的是0。

" . PHP_EOL.PHP_EOL);

$count = 3;

for ($i = 0; $i < $count; $i++) {
	$pid = pcntl_fork();
    if($pid == -1) {
    	fwrite(STDOUT, "Could not fork worker {$i}" . PHP_EOL);
        die();
    }
    else if(!$pid) {
    	fun($i, $count);
    	// 如果不使用下面的方式退出,将会出现什么呢,经测试,下面是我们得出的结果。
        // break;
        // exit;
    } else {
    	fwrite(STDOUT, "父进程 " . $i . PHP_EOL);
    }
}


function fun($i, $count)
{
	// global $num;
	$num = $i;
	$jc = exec('echo $$');
	$time = date('Y-m-d H:i:s');
	fwrite(STDOUT, "进程:$jc  计数:$num - $count  时间:$time" . PHP_EOL);
	fwrite(STDOUT, "start > " . date('Y-m-d H:i:s') . PHP_EOL);
	fwrite(STDOUT, "~ 3s ~" . PHP_EOL);

	sleep(3);
	fwrite(STDOUT, "enddd $i < " . date('Y-m-d H:i:s') . PHP_EOL.PHP_EOL);
}

父进程循环 从0开始 3次 创建3个子进程 产生下面第一部分
i = 0/1/2 结束循环

子0进程下面的循环 从1开始循环 能循环2次 创建2个子进程 产生下面第二部分(由第一子进程产生) 和 第三部分(由第二子进程产生)

子1进程下面的循环 从2开始循环 能循环1次 创建1个子进程 产生下面第四部分

子2进程下面的循环 没有循环 退出了(什么都没做)

由此分析可见PHP的这个子进程机制的特点:
继承父进程的“运行上下文”即变量和环境都是直接继承了,并且各个子进程相互,不受影响。

[root@iZ28yn5lehbZ x]# x=sf php d3.php
stat>

父进程 0
父进程 1
父进程 2
进程:25608  计数:0 - 3  时间:2016-08-15 08:35:47
start > 2016-08-15 08:35:47
~ 3s ~
进程:25610  计数:2 - 3  时间:2016-08-15 08:35:47
start > 2016-08-15 08:35:47
~ 3s ~
进程:25611  计数:1 - 3  时间:2016-08-15 08:35:47
start > 2016-08-15 08:35:47
~ 3s ~
enddd 1 < 2016-08-15 08:35:50
enddd 2 < 2016-08-15 08:35:53
enddd 0 < 2016-08-15 08:35:50



父进程 1
父进程 2
进程:25643  计数:1 - 3  时间:2016-08-15 08:35:50
start > 2016-08-15 08:35:50
~ 3s ~
进程:25644  计数:2 - 3  时间:2016-08-15 08:35:50
start > 2016-08-15 08:35:50
~ 3s ~
enddd 1 < 2016-08-15 08:35:53
enddd 2 < 2016-08-15 08:35:53


父进程 2
进程:25646  计数:2 - 3  时间:2016-08-15 08:35:50
start > 2016-08-15 08:35:50
~ 3s ~
enddd 2 < 2016-08-15 08:35:50


父进程 2
进程:25663  计数:2 - 3  时间:2016-08-15 08:35:53
start > 2016-08-15 08:35:53
~ 3s ~
enddd 2 < 2016-08-15 08:35:56

php获取子进程ID

	$jc = exec('echo $$');      // 这方式获取的不是当前PHP脚本执行的进程ID
    $child_id = getmypid();     // 这个才是当前PHP脚本执行的进程ID

参见:https://segmentfault.com/q/1010000004634861

父进程:17488 字进程:17489 计数:0
父进程:17488 字进程:17490 计数:1
进程:17489  计数:0 - 3  时间:2016-08-15 16:55:22
start > 2016-08-15 16:55:22
~ 3s ~
父进程:17488 字进程:17491 计数:2
进程:17490  计数:1 - 3  时间:2016-08-15 16:55:22
start > 2016-08-15 16:55:22
~ 3s ~
进程:17491  计数:2 - 3  时间:2016-08-15 16:55:22
start > 2016-08-15 16:55:22
~ 3s ~
[root@iZ28yn5lehbZ x]# enddd 0 < 2016-08-15 16:55:25

enddd 1 < 2016-08-15 16:55:25

enddd 2 < 2016-08-15 16:55:25

上面这个父进程执行部分是否先输出来,有时并无实际规律,理论上和实际上不一样,原因是可能需要考虑进程在CPU资源分配使用上面。(但好像父进程 计数:0永远在第一,也就是说在这个开辟子进程的结构中,父进程是首次执行的。)

$status = '';

$pid = pcntl_fork();
//父进程和子进程都会执行下面代码
if ($pid == -1) {
    //错误处理:创建子进程失败时返回-1.
     die('could not fork');
} else if ($pid) {

     //父进程会得到子进程号,所以这里是父进程执行的逻辑
     // pcntl_wait($status); //等待子进程中断,防止子进程成为僵尸进程。

     fwrite(STDOUT, "父进程" . PHP_EOL);
} else {
     //子进程得到的$pid为0, 所以这里是子进程执行的逻辑。
     fwrite(STDOUT, "子进程" . PHP_EOL);
}

分析

1、父进程执行完毕就退出了,但是这个退出不会结束可能还没执行完成的子进程,也就是说子进程会变成僵尸进程,这并不像 结束了ssh就结束了bash,就结束了我们的脚本那样。(这个也确实是要成为僵尸进程,不然孩子刚生出来还没玩够就要死了)
2、输出顺序为:
父进程
子进程
如果将pcntl_wait这一行注释掉,输出顺序就为
子进程
父进程
测试:

父进程和子进程 都从fork的位置开始向下继续执行,所以这个硬要说规律也不好说,这个是CPU指令执行资源的事了。
php的多进程实验分析_第1张图片

你可能感兴趣的:(php)