搜索
首页后端开发php教程php pcntl 实践填坑

PHP 可以通过pcntl 扩展实现多进程编程, 而网上关于如何通过pcntl 创建多进程的在这里就不表了, 我主要说说关于pcntl_fork的一个坑和相关的比较生僻的几个函数的使用方式, 这也是通过挖坑和填坑得出的结论。
闲言碎语不要讲, 直接开始

pcntl_fork

在实践中, 我在使用php进行多进程实践的模型大概如下, 期待的是每个子进程都能创建一个与之对应文件, 最后父进程创建一个属于父进程的文件,代码如下(有坑):

$pid_dir = __dir__."/pid_files";for($i=0; $i<3; $i++){    $pid = pcntl_fork();    if($pid == -1){        var_dump("fork failed");    }    if(!$pid){        //子进程代码        $pid = posix_getpid();        $ppid = posix_getppid();        $r = rand(0,100);  //随机数        touch("$pid_dir/fork_child_process_{$i}_{$ppid}_{$pid}_{$r}");    }} $pid = posix_getpid();$ppid = posix_getppid();$r = rand(0,100); //随机数touch("$pid_dir/fork_process_pid_{$ppid}_{$pid}_$r");

上面的代码我通过循环创建3个子进程, 每个进程创建一个文件,完成后到最后, 父进程创建一个属于他自己的文件,所以, 最后应该会创建出4个文件, 但事实并非如此:

fork_child_process_0_62656_62658_39fork_child_process_1_62656_62659_51fork_child_process_1_62658_62660_22fork_child_process_2_62656_62661_91fork_child_process_2_62658_62662_22fork_child_process_2_62659_62663_82fork_child_process_2_62660_62664_59fork_process_pid_62225_62656_48fork_process_pid_62656_62658_22fork_process_pid_62656_62659_82fork_process_pid_62656_62661_65fork_process_pid_62658_62660_59fork_process_pid_62658_62662_59fork_process_pid_62659_62663_61fork_process_pid_62660_62664_10

为何会出现上面的结果, 这是因为在fork之后, 原有的进程会分裂为两个进程, 一个主进程, 一个子进程, fork后面所有的代码都是共享的, 虽然通过fork的返回值可以判断是主进程还是子进程来执行相应的子进程或主进程逻辑,但之后子进程自己又走到了for循环的部分, 子进程自己有创建了子进程, 所以上面看到了多个child_process 文件, 至于为什么是7个,
来分析一下。

=====================华丽的分割线=============================

循环变量$i, 当$i为0时, 会产生一个主进程a(不变)和一个子进程aa,这个子进程创建了一个子进程文件,即fork_child_process_0_62656_62658_39, 主进程a继续循环, 即$i=1, 又创建了一个子进程ab, 他创建了fork_child_process_1_62656_62659_51, 主进程a继续循环$i=2, 又创建了一个子进程ac, 他创建了fork_child_process_2_62656_62661_91这里可以看到62656就是主进程a的pid.

至此, 主进程a的循环完毕, 在看看a创建的第一个子进程aa, aa在创建之后, 创建好了上面的子进程文件之后并不会什么也不做, 他也会继续走for的循环, 而且继承了主进程a的循环变量, 也就是$i的值为0,所以aa进程下一次的循环的$i就是1, 然后aa继续创建了子进程aaa,从而创建文件fork_child_process_1_62658_62660_22,aa继续,$i=2, 又创建了一个子进程aab, 这个子进程创建了文件fork_child_process_2_62658_62662_22, 这里可以看到aaa和aab的ppid就是aa的pid 62658,
同理aaa,aab 也继承了aa的$i值,这时$i的值为1, 当继续循环时, $i 就变成了2, 也就只能循环一次了,相应aaa,aab 创建了子进程文件fork_child_process_2_62659_62663_82(aaaa),fork_child_process_2_62660_62664_59(aaba),而他们相应的父进程就是aaa(62659)和aab(62660).

至此, for循环中的多进程逻辑完成了, 也就是为何产生了第一部分的7个文件

=====================华丽的分割线=============================

而至于为何第二部分是8个文件, 各位可以自己思考一下, 注意, 无论主进程还是子进程, 在for循环完毕之后会继续往下走, 知道这一点就好理解了。

在实际的代码中, 我就犯了这种错误。
那如何解决上面的问题呢, 只要在子进程执行的最后exit就好啦,

fork_child_process_0_63219_63221_66fork_child_process_1_63219_63222_88fork_child_process_2_63219_63223_22fork_process_pid_62225_63219_77

继续,那么在网上看到很多多进程编程中使用pcntl_waitpid, 并不了解他是做什么的,且相应的例子很少, 我暂且来说说我的理解

pcntl_waitpid

等待或返回fork的子进程状态。
多进程的主进程创建了子进程,那主进程如何确认子进程的状态呢。 假如主进程需要根据子进程的状态做不同的处理呢, 这里的状态包括子进程被kill掉,或变成僵尸进程等。 pcntl_waitpid就可以获取子进程的状态码, 通过这个状态码, 就可知道子进程处于什么状态
他的用法:

int pcntl_waitpid ( int $pid , int &$status [, int $options = 0 ] )

返回的值可以是-1,0或者 >0的值, 如果是-1, 表示子进程出错, 如果>0表示子进程已经退出且值是退出的子进程pid,至于如何退出, 可以通过$status状态码反应。 那什么时候返回0呢, 只有在option 参数为 WNOHANG且子进程正在运行时0, 也就是说当设置了options=WNOHANG时, 如果子进程还没有退出, 此时pcntl_waitpid就会返回0
另外, 如果不设置这个参数为WNOHANG, pcntl_waitpid 就会阻塞运行, 直到子进程退出, 至于option的另外一个值WUNTRACED, 暂未理解, 不表

那么如何根据$status(状态码)判断进程是如何退出呢, 如下(参数都是$status)

pcntl_wifexited

这个函数可以根据$status 判断进程是否正常退出, 何为正常退出, 比如exit

pcntl_wexitstatus

这个函数仅在pcntl_wifexited 返回True(即正常退出)时有效, 且返回子进程退出的返回状态码, 这个返回状态码可以通过exit($s)的参数($s必须为整数时)定义

pcntl_wifsignaled

检查子进程状态码是否代表由于某个信号而中断, 比如是不是我们给他发送了term, int 等信号了

pcntl_wexitstatus

假如是发送信号而导致子进程中断, 那么这个信号是什么信号呢, 这个函数就是获取这个信号的

pcntl_wifstopped

仅当option选项为WUNTRACED时有效, 未理解, 不表

pcntl_wtermsig

同上

综合实例代码:

$res = pcntl_waitpid($pid, $status, WNOHANG);//FileLog::log("pid is $pid; wait result is $res");if($res == -1 || $res > 0){    if(!pcntl_wifexited($status)){        //进程非正常退出        FileLog::log("service stop unusally; pid is $pid");    }else{        //获取进程终端的退出状态码;        $code = pcntl_wexitstatus($status);        FileLog::log("service stop code: $code;pid is $pid ");    }    if(pcntl_wifsignaled($status)){        //不是通过接受信号中断        FileLog::log("service stop not by signal;pid is $pid ");    }else{        $signal = pcntl_wtermsig($status);        FileLog::log("service stop by signal $signal;pid is $pid");    }}

上面的这个代码就通过根据pcntl_waitpid的返回结果和状态码对子进程因为不同原因中断做了不同的处理

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
PHP与Python:了解差异PHP与Python:了解差异Apr 11, 2025 am 12:15 AM

PHP和Python各有优势,选择应基于项目需求。1.PHP适合web开发,语法简单,执行效率高。2.Python适用于数据科学和机器学习,语法简洁,库丰富。

php:死亡还是简单地适应?php:死亡还是简单地适应?Apr 11, 2025 am 12:13 AM

PHP不是在消亡,而是在不断适应和进化。1)PHP从1994年起经历多次版本迭代,适应新技术趋势。2)目前广泛应用于电子商务、内容管理系统等领域。3)PHP8引入JIT编译器等功能,提升性能和现代化。4)使用OPcache和遵循PSR-12标准可优化性能和代码质量。

PHP的未来:改编和创新PHP的未来:改编和创新Apr 11, 2025 am 12:01 AM

PHP的未来将通过适应新技术趋势和引入创新特性来实现:1)适应云计算、容器化和微服务架构,支持Docker和Kubernetes;2)引入JIT编译器和枚举类型,提升性能和数据处理效率;3)持续优化性能和推广最佳实践。

您什么时候使用特质与PHP中的抽象类或接口?您什么时候使用特质与PHP中的抽象类或接口?Apr 10, 2025 am 09:39 AM

在PHP中,trait适用于需要方法复用但不适合使用继承的情况。1)trait允许在类中复用方法,避免多重继承复杂性。2)使用trait时需注意方法冲突,可通过insteadof和as关键字解决。3)应避免过度使用trait,保持其单一职责,以优化性能和提高代码可维护性。

什么是依赖性注入容器(DIC),为什么在PHP中使用一个?什么是依赖性注入容器(DIC),为什么在PHP中使用一个?Apr 10, 2025 am 09:38 AM

依赖注入容器(DIC)是一种管理和提供对象依赖关系的工具,用于PHP项目中。DIC的主要好处包括:1.解耦,使组件独立,代码易维护和测试;2.灵活性,易替换或修改依赖关系;3.可测试性,方便注入mock对象进行单元测试。

与常规PHP阵列相比,解释SPL SplfixedArray及其性能特征。与常规PHP阵列相比,解释SPL SplfixedArray及其性能特征。Apr 10, 2025 am 09:37 AM

SplFixedArray在PHP中是一种固定大小的数组,适用于需要高性能和低内存使用量的场景。1)它在创建时需指定大小,避免动态调整带来的开销。2)基于C语言数组,直接操作内存,访问速度快。3)适合大规模数据处理和内存敏感环境,但需谨慎使用,因其大小固定。

PHP如何安全地上载文件?PHP如何安全地上载文件?Apr 10, 2025 am 09:37 AM

PHP通过$\_FILES变量处理文件上传,确保安全性的方法包括:1.检查上传错误,2.验证文件类型和大小,3.防止文件覆盖,4.移动文件到永久存储位置。

什么是无效的合并操作员(??)和无效分配运算符(?? =)?什么是无效的合并操作员(??)和无效分配运算符(?? =)?Apr 10, 2025 am 09:33 AM

JavaScript中处理空值可以使用NullCoalescingOperator(??)和NullCoalescingAssignmentOperator(??=)。1.??返回第一个非null或非undefined的操作数。2.??=将变量赋值为右操作数的值,但前提是该变量为null或undefined。这些操作符简化了代码逻辑,提高了可读性和性能。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器