PHP多进程学习(三)__代码案例来了解父进程与子进程的执行顺序
pcntl_fork创建子进程成功的话,系统就有了2个进程,一个为父进程,一个为子进程,父进程和子进程都继续向下执行,子进程的id号为$pid(父进程会获取子进程的$pid也就是$pid不为0,而子进程会获取$pid为0)在系统运行到$pid = pcntl_fork();时,在这个地方进行分支,父子进程各自开始运行各自的程序代码(通过if else语句判断$pid我们就可以在指定位置写上不同的逻辑代码)。
代码的运行结果是parent 和child,很奇怪吧,为什么一个if和else互斥的代码中,都输出了结果?其实是像上边所说的,代码在pcntl_fork时,一个父进程运行parent,一个子进程运行了child。在代码结果上就显示了parent和child。至于谁先谁后的问题,这得要看系统资源的分配了。
案例①
<?php
$pid = pcntl_fork(); if($pid == -) {
//错误处理:创建子进程失败时返回-1.
die('fork error');
} else if ($pid) {
//父进程会得到子进程号,所以这里是父进程执行的逻辑
echo "parent \n";
//等待子进程中断,防止子进程成为僵尸进程。
pcntl_wait($status);
} else {
//子进程得到的$pid为0, 所以这里是子进程执行的逻辑。
echo "child \n"; exit;
}
# php fork.php //结果
parent
child
上述代码会经过多次执行,分别输出parent和child。貌似是优先执行父进程。那么输出的parent和child是否会有顺序之分?是父进程会先执行?下面继续测试。。。
案例②
<?php
$pid = pcntl_fork(); if($pid == -) {
die('fork error');
} else if ($pid) {
sleep();
echo "parent \n";
pcntl_wait($status);
} else {
echo "child \n"; exit;
}
# php fork.php //结果
child
parent
我们在父进程中通过sleep来延缓执行,看看效果。
结果是,很快输出了child,等待了接近3秒后,才输出parent。所以父进程和子进程的执行是相对独立的,没有先后之分。
那么问题又来了?pcntl_wait是做什么用的?
会挂起当前进程,直到子进程退出,如果子进程在调用此函数之前就已退出,此函数会立刻返回。子进程使用的资源将被释放。
案例③
<?php
$pid = pcntl_fork(); if($pid == -) {
die('fork error');
} else if ($pid) {
pcntl_wait ($status);
echo "parent \n";
} else {
sleep();
echo "child \n"; exit;
}
# php fork.php //结果
child
parent
上述代码,我们可以看到,父进程执行pcntl_wait时就已经挂起,直到等待3秒后输出child,子进程退出后。父进程继续执行,输出parent。
案例④
<?php
define('FORK_NUMS', ); $pids = array(); for($i = ; $i < FORK_NUMS; ++$i) {
$pids[$i] = pcntl_fork();
if($pids[$i] == -) {
die('fork error');
} else if ($pids[$i]) {
pcntl_waitpid($pids[$i], $status);
echo "pernet \n";
} else {
sleep();
echo "child id:" . getmypid() . " \n";
exit;
}
}
# php fork.php //结果
child id:
pernet
child id:
pernet
child id:
pernet
上述代码,我们创建3个子进程,父进程分别挂起等待子进程结束后,输出parent。
案例⑤
<?php
define('FORK_NUMS', ); $pids = array(); for($i = ; $i < FORK_NUMS; ++$i) {
$pids[$i] = pcntl_fork();
if($pids[$i] == -) {
die('fork error');
} else if ($pids[$i]) { } else {
sleep();
echo "child id:" . getmypid() . " \n";
exit;
}
} foreach($pids as $k => $v) {
if($v) {
pcntl_waitpid($v, $status);
echo "parent \n";
}
}
# php fork.php //结果
child id:
child id:
child id:
parent
parent
parent
为什么上述代码跟例4的输出结果不一样?
我们可以看到案例⑤的pcntl_waitpid函数放在了foreach中,foreach代码是在主进程中,也就是父进程的代码中。当执行foreach时,可能子进程已经全部执行完毕并退出。pcntl_waitpid会立刻返回,连续输出三个parent。
在子进程中,需通过exit来退出,不然会产生递归多进程,父进程中不需要exit,不然会中断多进程。
案例⑥
<?php
define('FORK_NUMS', );
$pids = array();
$fp = fopen('./test.log', 'wb');
$num = ;
for($i = ; $i < FORK_NUMS; ++$i) {
$pids[$i] = pcntl_fork();
if($pids[$i] == -) {
die('fork error');
} else if ($pids[$i]) {
} else {
for($i = ; $i < ; ++$i) {
flock($fp, LOCK_EX);
fwrite($fp, getmypid() . ' : ' . date('Y-m-d H:i:s') . " : {$num} \r\n");
flock($fp, LOCK_UN);
echo getmypid(), ": success \r\n";
++$num;
}
exit;
}
}
foreach($pids as $k => $v) {
if($v) {
pcntl_waitpid($v, $status);
}
}
fclose($fp);
# php fork.php //结果
: success
: success
: success
: success
: success
: success
: success
: success
: success
: success
: success
: success
: success
: success
: success
//test.log 日志内容
: -- :: :
: -- :: :
: -- :: :
: -- :: :
: -- :: :
: -- :: :
: -- :: :
: -- :: :
: -- :: :
: -- :: :
: -- :: :
: -- :: :
: -- :: :
: -- :: :
: -- :: :
我们可以看到三个子进程的pid,它们分别执行了5次,时间几乎是在同时。但是$num的值并没像我们期望的那样从1-15进行递增。子进程中的变量是各自独立的,互不影响。子进程会自动复制父进程空间里的变量。
参考原文https://www.cnblogs.com/jkko123/p/6351690.html
PHP多进程学习(三)__代码案例来了解父进程与子进程的执行顺序的更多相关文章
- PHP多进程学习(一)__来初步了解一下PHP多进程及简单demo
php是一门单进程弱类型的语言,PHP处理多并发主要是依赖服务器或PHP-FPM的多进程及它们进程的复用,多进程的作用优点大家可以去网上了解,PHP实现多进程在实际项目中意义也是不容小觑的.比如:日常 ...
- Linux内核学习笔记(2)-- 父进程和子进程及它们的访问方法
Linux系统中,进程之间有一个明显的继承关系,所有进程都是 PID 为1的 init 进程的后代.内核在系统启动的最后阶段启动 init 进程.该进程读取系统的初始化脚本(initscript)并执 ...
- Python 多线程、多进程 (三)之 线程进程对比、多进程
Python 多线程.多进程 (一)之 源码执行流程.GIL Python 多线程.多进程 (二)之 多线程.同步.通信 Python 多线程.多进程 (三)之 线程进程对比.多线程 一.多线程与多进 ...
- python 多进程的启动和代码执行顺序
对照着廖雪峰的网站学习Python遇到些问题: 在进程中,父进程创建子进程时发现,显示不是按照顺序显示,疑问? 参照代码如下: from multiprocessing import Pool imp ...
- Unix网络编程代码 第13章 守护进程和inetd超级服务器
1. 概述 守护进程是在后台运行且不与任何控制终端关联的进程.unix系统通常有很多守护进程在后台运行,执行不同的管理任务. 守护进程没有控制终端通常源于它们由系统初始化脚本启动.然而守护进程也 ...
- Python之路(第三十六篇)并发编程:进程、同步异步、阻塞非阻塞
一.理论基础 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一.操作系统的其他所有内容都是围绕进程的概念展开的. 即使可以利用的cpu只有一个(早期的 ...
- php 多进程 父进程的阻塞与非阻塞
php中进程的阻塞,主要是父进程等待子进程退出. 1.php代码如下: <?php //定义进程数量 define('FORK_NUMS', 5); //用于保存进程pid $pids = ar ...
- Java类中代码的执行顺序 静态代码块>构造代码块>构造方法
一:静态代码块 注意是代码块,不是静态函数.函数要调用才执行,代码块加载就执行,一般是静态变量的声明与初始化.被static修饰的代码块(赋值.输出操作等).类中静态语句块仅在类加载时被执行一次 如 ...
- 【Java基础】继承中的代码块和构造方法的执行顺序探索
本文讲述有关一个类的静态代码块,构造代码块,构造方法的执行流程问题.首先来看一个例子 /** * Created by lili on 15/10/19. */ class Person{ stati ...
随机推荐
- php上传文件中文文件名乱码的解决方法
文件上传是我们在处理表单提交时候最常用的功能之一,今天写了一个小小的demo,如下: 先看结构: html为表单提交的页面,php为处理表单的文件,upload为上传文件所放的位置 html: < ...
- Mybatis中的foreach
<delete id="deleteByParam"> DELETE FROM YZ_SECURITIES_CURRENCY WHERE ID IN <forea ...
- 【BZOJ3939】[Usaco2015 Feb]Cow Hopscotch 动态规划+线段树
[BZOJ3939][Usaco2015 Feb]Cow Hopscotch Description Just like humans enjoy playing the game of Hopsco ...
- [SQL]批量 更改字符集脚本,批量查询约束,批量查询索引
How to change collation of all database objects in SQL Server. Have you encountered a problem where ...
- intelliij jdea 的file没有setting的解决方法
- Yii 各种url地址写法
echo Url::home(); 生成入口地址/yii2test/frontend/web/index.php: echo Url::base();生成入口文件夹地址:/yii2test/fron ...
- 【转】SQL Server编程游标
在关系数据库中,我们对于查询的思考是面向集合的.而游标打破了这一规则,游标使得我们思考方式变为逐行进行.对于类C的开发人员来着,这样的思考方式会更加舒服. 正常面向集合的思维方式是: 而对于游标来说: ...
- Drools规则引擎
一.简介 Drools is a Business Rules Management System (BRMS) solution. It provides a core Business Rules ...
- Meaning of “const” last in a C++ method declaration?
函数尾部的const是什么意思? 1 Answer by Jnick Bernnet A "const function", denoted with the keyword co ...
- 数据字典Data Dict
数据字典 所有的数据表都属于数据库对象,每当创建一张数据表的时候,会自动在指定的数据字典表执行一个增加语句(这个增加语言我们是不知道的),数据字典的数据操作只能通过命令完成,不能直接使用SQL完成. ...