php7内核剖析(浅析PHP7的多进程及实例源码)
php7内核剖析
浅析PHP7的多进程及实例源码准备
我们都知道PHP是单进程执行的,PHP处理多并发主要是依赖服务器或PHP-FPM的多进程及它们进程的复用,但PHP实现多进程也意义重大,尤其是在后台Cli模式下处理大量数据或运行后台DEMON守护进程时,多进程的优势不用多说。
PHP的多线程也曾被人提及,但进程内多线程资源共享和分配的问题难以解决。PHP也有多线程想关的扩展 pthreads ,但据说不太稳定,且要求环境为线程安全,所用不多。
以前PHP群里的一位大神曾指导说后台PHP想进阶必然避不开多进程,正好公司里的守护进程也应用了PHP的多进程,结合着谷哥的各种资料和手册,总算理解了多进程,并自己写了一个小demo(在linux系统上实现的),用此文总结一下,如有错漏,谢谢提出。
要实现PHP的多进程,我们需要两个扩展 pcntl 和 posix,安装方法这里不再赘述。
在php中我们使用pcntl_fork()来创建多进程(在*NIX系统的C语言编程中,已有进程通过调用fork函数来产生新的进程)。fork出来新进程则成为子进程,原进程则成为父进程,子进程拥有父进程的副本。这里要注意:
• 子进程与父进程共享程序正文段
• 子进程拥有父进程的数据空间和堆、栈的副本,注意是副本,不是共享
• 父进程和子进程将继续执行fork之后的程序代码
• fork之后,是父进程先执行还是子进程先执行无法确认,取决于系统调度(取决于信仰)
这里说子进程拥有父进程数据空间以及堆、栈的副本,实际上,在大多数的实现中也并不是真正的完全副本。更多是采用了COW(Copy On Write)即写时复制的技术来节约存储空间。简单来说,如果父进程和子进程都不修改这些 数据、堆、栈 的话,那么父进程和子进程则是暂时共享同一份 数据、堆、栈。只有当父进程或者子进程试图对 数据、堆、栈 进行修改的时候,才会产生复制操作,这就叫做写时复制。
在调用完pcntl_fork()后,该函数会返回两个值。在父进程中返回子进程的进程ID,在子进程内部本身返回数字0。由于多进程在apache或者fpm环境下无法正常运行,所以大家一定要在php cli环境下执行代码。
创建子进程
创建PHP子进程是多进程的开始,我们需要pcntl_fork()函数;
fork函数详解
pcntl_fork() — 在当前进程当前位置产生分支(子进程)。此函数创建了一个新的子进程后,子进程会继承父进程当前的上下文,和父进程一样从pcntl_fork() 函数处继续向下执行,只是获取到的pcntl_fork() 的返回值不同,我们便能从判断返回值来区分父进程和子进程,分配父进程和子进程去做不同的逻辑处理。
pcntl_fork() 函数成功执行时会在父进程返回子进程的进程id(pid),因为系统的初始进程init进程的pid为1,后来产生进程的pid都会大于此进程,所以我们可以通过判断pcntl_fork()的返回值大于1来确实当前进程是父进程;而在子进程中,此函数的返回值会是固定值0,我们也可以通过判断pcntl_fork()的返回值为0来确定子进程;而pcntl_fork()函数在执行失败时,会在父进程返回-1,当然也不会有子进程产生。
fork进程实例
fork子进程
|
$ppid = posix_getpid(); $pid = pcntl_fork(); if ( $pid == -1) { throw new Exception( 'fork child process fail' ); } elseif ( $pid > 0) { cli_set_process_title( "我是父 process,pid is : {$ppid}." ); sleep(30); } else { $cpid = posix_getpid(); cli_set_process_title( "我是 {$ppid} 子的 process,我的 process pid is : {$cpid}." ); sleep(30); } |
说明:
posix_getpid():返回当前进程 id
cli_set_process_title('进程名称'):为当前进程取一个响亮的名字。
运行这个例子,我们便能看到当前两个PHP进程了。
|
www@iZ2zec3dge6rwz2uw4tveuZ:~/test$ ps aux|grep -v grep |grep 我 www 18026 0.5 1.2 204068 25772 pts/0 S+ 14:08 0:00 我是父 process,pid is : 18026. www 18027 0.0 0.3 204068 6640 pts/0 S+ 14:08 0:00 我 18026 子的 process,我的 process pid is : 18027. |
第一段代码,在程序从pcntl_fork()后父进程和子进程将各自继续往下执行代码:
|
$pid = pcntl_fork(); if ( $pid > 0 ){ echo "我是父亲" .PHP_EOL; } else if ( 0 == $pid ) { echo "我是儿子" .PHP_EOL; } else { echo "fork失败" .PHP_EOL; } |
结果:
|
www@iZ2zec3dge6rwz2uw4tveuZ:~/test$ php 123.php 我是父亲 我是儿子 |
第二段代码,用来说明子进程拥有父进程的数据副本,而并不是共享:
|
// 初始化一个 number变量 数值为1 $number = 1; $pid = pcntl_fork(); if ( $pid > 0) { $number += 1; echo "我是父亲,number+1 : { $number }" . PHP_EOL; } else if (0 == $pid ) { $number += 2; echo "我是儿子,number+2 : { $number }" . PHP_EOL; } else { echo "fork失败" . PHP_EOL; } |
结果
|
www@iZ2zec3dge6rwz2uw4tveuZ:~/test$ php 1234.php 我是父亲,number+1 : { 2 } 我是儿子,number+2 : { 3 } |
- apachephp环境搭建(apache集成php7.3.5的详细步骤)
- 宝塔linux面板php7.0安装不上(宝塔面板php.ini文件在哪里找)
- 在php中与数据库连接的技术(PHP7.0连接DB操作实例分析基于mysqli)
- phpstudy使用教程学习(phpStudy 2016 使用教程详解支持PHP7)
- php7语法代码规范(PHP7新功能总结)
- php7.4编译安装(PHP7.3.10编译安装教程)
- php中的内置函数(php7下的filesize函数)
- php7.4 废弃功能(浅析PHP7 的垃圾回收机制)
- linux如何安装php7.1.5环境(vmware linux系统安装最新的php7图解)
- php7 入门(php7新特性的理解和比较总结)
- php7优化技巧(php7性能提升的原因详解)
- yii2支持php7.2吗(Yii框架通过请求组件处理get,post请求的方法分析)
- php7处理方案(PHP7 安装event扩展的实现方法)
- php7.4类型属性实例详解(PHP 7.4中使用预加载的方法详解)
- php自定义函数返回多少个值(PHP7导出Excel报ERR_EMPTY_RESPONSE解决方法)
- php教程7.10.6学习(php5.6.x到php7.0.x特性小结)
- 苹果自研芯片跑分对比 A16芯片排名靠后,M1系列霸榜(苹果自研芯片跑分对比)
- X86处理器的梦魇 苹果M1自研芯片到底有多强(苹果M1自研芯片到底有多强)
- 泰剧《爱欲之神》Boom kitkong和Great合体杂志(泰剧爱欲之神Boomkitkong和Great合体杂志)
- 素人恋爱综艺火药味十足 男生为赢得芳心集体扯头花,真是出好戏(素人恋爱综艺火药味十足)
- 《囧妈》为何受抵制 春节七部影片撤档背后的责任与博弈(囧妈为何受抵制)
- 提醒 2019年起河南驾考要开设科目五 官方回应来了(2019年起河南驾考要开设科目五)
热门推荐
- PowerDesigner逆向生成pdm
- php运行模式图解(php策略模式简单示例分析区别于工厂模式)
- js特效星空(ThingJS粒子特效一键实现雨雪效果)
- vue双向数据绑定js如何实现(纯JS如何实现vue.js下的双向绑定功能)
- 无盘服务器配置要求(云服务器配置怎么选)
- mysql各种类型设置(MySQL sql_mode的使用详解)
- html5canvas功能介绍(Html5 Canvas实现图片标记、缩放、移动和保存历史状态功能 附转换公式)
- MySQL主从状态检查的实现(MySQL主从状态检查的实现)
- 无法打开sql server的连接(由于系统错误 126 SQL Server,指定驱动程序无法加载)
- 群晖docker搭建代理服务(群晖NAS利用Docker容器搭建KMS激活服务器实现激活windows系统和office操作步骤)
排行榜
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9