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的返回结果和状态码对子进程因为不同原因中断做了不同的处理

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











Laravel은 직관적 인 플래시 방법을 사용하여 임시 세션 데이터 처리를 단순화합니다. 응용 프로그램에 간단한 메시지, 경고 또는 알림을 표시하는 데 적합합니다. 데이터는 기본적으로 후속 요청에만 지속됩니다. $ 요청-

PHP 클라이언트 URL (CURL) 확장자는 개발자를위한 강력한 도구이며 원격 서버 및 REST API와의 원활한 상호 작용을 가능하게합니다. PHP CURL은 존경받는 다중 프로모토콜 파일 전송 라이브러리 인 Libcurl을 활용하여 효율적인 execu를 용이하게합니다.

Alipay PHP ...

Laravel은 간결한 HTTP 응답 시뮬레이션 구문을 제공하여 HTTP 상호 작용 테스트를 단순화합니다. 이 접근법은 테스트 시뮬레이션을보다 직관적으로 만들면서 코드 중복성을 크게 줄입니다. 기본 구현은 다양한 응답 유형 단축키를 제공합니다. Illuminate \ support \ Facades \ http를 사용하십시오. http :: 가짜 ([ 'google.com'=> 'Hello World', 'github.com'=> [ 'foo'=> 'bar'], 'forge.laravel.com'=>

고객의 가장 긴급한 문제에 실시간 인스턴트 솔루션을 제공하고 싶습니까? 라이브 채팅을 통해 고객과 실시간 대화를 나누고 문제를 즉시 해결할 수 있습니다. 그것은 당신이 당신의 관습에 더 빠른 서비스를 제공 할 수 있도록합니다.

기사는 PHP 5.3에 도입 된 PHP의 LSB (Late STATIC BING)에 대해 논의하여 정적 방법의 런타임 해상도가보다 유연한 상속을 요구할 수있게한다. LSB의 실제 응용 프로그램 및 잠재적 성능

기사는 입력 유효성 검사, 인증 및 정기 업데이트를 포함한 취약점을 방지하기 위해 프레임 워크의 필수 보안 기능을 논의합니다.

이 기사에서는 프레임 워크에 사용자 정의 기능 추가, 아키텍처 이해, 확장 지점 식별 및 통합 및 디버깅을위한 모범 사례에 중점을 둡니다.
