摘要:用于創(chuàng)建子進(jìn)程。該函數(shù)阻塞當(dāng)前進(jìn)程,只到當(dāng)前進(jìn)程的一個(gè)子進(jìn)程退出或者收到一個(gè)結(jié)束當(dāng)前進(jìn)程的信號(hào)。注意處需要注意子進(jìn)程需要防止子進(jìn)程也進(jìn)入循環(huán)。如果沒有,最終創(chuàng)建的子進(jìn)程不只個(gè)。
本系列文章將向大家講解pcntl_*系列函數(shù),從而更深入的理解進(jìn)程相關(guān)知識(shí)。
PCNTL在PHP中進(jìn)程控制支持默認(rèn)是關(guān)閉的。您需要使用 --enable-pcntl 配置選項(xiàng)重新編譯PHP的 CGI或CLI版本以打開進(jìn)程控制支持。
如果自帶的PHP沒有安裝pcntl擴(kuò)展,可以下載相同版本的源碼,進(jìn)入ext/pcntl使用phpize編譯安裝。
Note: 此擴(kuò)展在 Windows 平臺(tái)上不可用。pcntl_fork
int pcntl_fork ( void )
用于創(chuàng)建子進(jìn)程。成功時(shí),在父進(jìn)程執(zhí)行線程內(nèi)返回產(chǎn)生的子進(jìn)程的PID,在子進(jìn)程執(zhí)行線程內(nèi)返回0。失敗時(shí),在父進(jìn)程上下文返回-1,不會(huì)創(chuàng)建子進(jìn)程,并且會(huì)引發(fā)一個(gè)PHP錯(cuò)誤。
fork.php
命令行運(yùn)行:
$ php fork.php Parent process,pid 98, child pid 99 Child process,pid 99該例里父進(jìn)程還沒有來得及等子進(jìn)程運(yùn)行完畢就自動(dòng)退出了,子進(jìn)程由 init進(jìn)程接管。通過 ps -ef | grep php 看到子進(jìn)程還在運(yùn)行:
[root@9355490fe5da /]# ps -ef | grep php root 105 1 0 16:46 pts/0 00:00:00 php fork.php root 107 27 0 16:46 pts/1 00:00:00 grep php子進(jìn)程成為孤立進(jìn)程,ppid(父進(jìn)程id)變成1了。如果在父進(jìn)程里也加個(gè)sleep(5),你會(huì)看到子進(jìn)程ppid本來是大于1的,后來就變成1了。
注:如果是docker環(huán)境,孤立進(jìn)程的ppid可能是0。pcntl_waitpcntl_wait()函數(shù)用來讓父進(jìn)程等待子進(jìn)程退出,默認(rèn)情況下會(huì)阻塞主進(jìn)程。
阻塞模式緊接著上面的例子,如果想等子進(jìn)程運(yùn)行結(jié)束后父進(jìn)程再退出,該怎么辦?那就用到pcntl_wait了。
int pcntl_wait ( int &$status [, int $options = 0 ] )該函數(shù)阻塞當(dāng)前進(jìn)程,只到當(dāng)前進(jìn)程的一個(gè)子進(jìn)程退出或者收到一個(gè)結(jié)束當(dāng)前進(jìn)程的信號(hào)。
我們修改代碼:
此時(shí)再次運(yùn)行程序,父進(jìn)程就會(huì)一直等待子進(jìn)程運(yùn)行結(jié)束然后退出。
pcntl_waitpid()和pcntl_wait()功能相同。前者第一個(gè)參數(shù)支持指定pid參數(shù),當(dāng)指定-1作為pid的值等同于后者。int pcntl_waitpid ( int $pid , int &$status [, int $options = 0 ] )當(dāng)已知子進(jìn)程pid的時(shí)候,可以使用pcntl_waitpid()。這兩個(gè)函數(shù)返回退出的子進(jìn)程進(jìn)程號(hào)(>1),發(fā)生錯(cuò)誤時(shí)返回-1,如果提供了 WNOHANG 作為option(wait3可用的系統(tǒng))并且沒有可用子進(jìn)程時(shí)返回0。
返回值為退出的子進(jìn)程進(jìn)程號(hào)時(shí),想了解如何退出,可以通過 $status狀態(tài)碼反應(yīng)。
非阻塞模式pcntl_wait()默認(rèn)情況下會(huì)阻塞主進(jìn)程,直到子進(jìn)程執(zhí)行完畢才繼續(xù)往下運(yùn)行。如果設(shè)置最后一個(gè)參數(shù)為常量WNOHANG,那么就不會(huì)阻塞主進(jìn)程,而是繼續(xù)執(zhí)行后續(xù)代碼, 此時(shí) pcntl_waitpid 就會(huì)返回0。
示例:
0){ sleep(10);//此處為了方便看效果,實(shí)際不需要 break; } } }else{ $id = getmypid(); echo "Child process,pid {$id} "; sleep(2); }該示例里只有一個(gè)子進(jìn)程,看不出來非阻塞的好處,我們修改一下:
$pid) { // $res = pcntl_wait($status, WNOHANG); $res = pcntl_waitpid($pid, $status, WNOHANG);//#3 if ($res == -1 || $res > 0){ echo time()." Child process exit,pid {$pid} "; unset($child_pids[$key]); }else{ // echo time()." Wait End,pid {$pid} "; //#4 } } }#3處首先先去掉WNOHANG參數(shù),運(yùn)行:
$ php fork.1.php 1528637334 Parent process,pid 6600, child pid 6601 1528637334 Child process,pid 6601,sleep 2 1528637334 Parent process,pid 6600, child pid 6602 1528637334 Child process,pid 6602,sleep 2 1528637334 Parent process,pid 6600, child pid 6603 1528637334 Child process,pid 6603,sleep 1 1528637336 Child process exit,pid 6601 1528637336 Child process exit,pid 6602 1528637336 Child process exit,pid 6603我們看到,6603號(hào)進(jìn)程運(yùn)行時(shí)間最短,但是是最后回收。我們?cè)偌由?b>WNOHANG參數(shù),運(yùn)行:
$ php fork.1.php 1528637511 Parent process,pid 6695, child pid 6696 1528637511 Child process,pid 6696,sleep 2 1528637511 Parent process,pid 6695, child pid 6697 1528637511 Child process,pid 6697,sleep 1 1528637511 Parent process,pid 6695, child pid 6698 1528637511 Child process,pid 6698,sleep 3 1528637512 Child process exit,pid 6697 1528637513 Child process exit,pid 6696 1528637514 Child process exit,pid 66986697進(jìn)程最先回收!說明確實(shí)是異步非阻塞的。感興趣的朋友還可以開啟#4處代碼,未使用WNOHANG參數(shù)的時(shí)候,里面的代碼是不會(huì)運(yùn)行的。
注意:#2處需要注意子進(jìn)程需要exit,防止子進(jìn)程也進(jìn)入for循環(huán)。如果沒有exit(),最終創(chuàng)建的子進(jìn)程不只3個(gè)。
檢測(cè)status函數(shù)在 pcntl_wait和pcntl_waitpid兩個(gè)函數(shù)中的$status中存了子進(jìn)程的狀態(tài)信息,這個(gè)參數(shù)可以用于 pcntl_wifexited、pcntl_wifstopped、pcntl_wifsignaled、pcntl_wexitstatus、 pcntl_wtermsig、pcntl_wstopsig、pcntl_waitpid這些函數(shù)。
代碼片段:
while(1){ $res = pcntl_wait($status); if ($res == -1 || $res > 0){ if(!pcntl_wifexited($status)){ //進(jìn)程非正常退出 echo "service exit unusally; pid is $pid "; }else{ //獲取進(jìn)程終端的退出狀態(tài)碼; $code = pcntl_wexitstatus($status); echo "service exit code: $code;pid is $pid "; } if(pcntl_wifsignaled($status)){ //不是通過接受信號(hào)中斷 echo "service term not by signal;pid is $pid "; }else{ $signal = pcntl_wtermsig($status); echo "service term by signal $signal;pid is $pid "; } if(pcntl_wifstopped($status)){ echo "service stop not unusally;pid is $pid "; }else{ $signal = pcntl_wstopsig($status); echo "service stop by signal $signal;pid is $pid "; } break; }參考1、php多進(jìn)程 防止出現(xiàn)僵尸進(jìn)程
https://www.cnblogs.com/jkko1...
2、PCNTL函數(shù)族--PHP多進(jìn)程編程 (轉(zhuǎn))
https://www.cnblogs.com/zox20...
防盜版聲明:本文系原創(chuàng)文章,原發(fā)布于公眾號(hào)飛鴻影的博客(fhyblog)及博客園,轉(zhuǎn)載需作者同意。
歡迎關(guān)注公眾號(hào)及時(shí)獲取最新文章推送!
推薦!每月僅需$2.5,即可擁有配置SSD的VPS!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/28874.html
摘要:任何進(jìn)程在退出前使用退出都會(huì)變成僵尸進(jìn)程用于保存進(jìn)程的狀態(tài)等信息,然后由進(jìn)程接管。這時(shí)候就算手動(dòng)結(jié)束腳本程序也無法關(guān)閉這個(gè)僵尸子進(jìn)程了。那么子進(jìn)程結(jié)束后,沒有回收,就產(chǎn)生僵尸進(jìn)程了。本小節(jié)我們通過安裝信號(hào)處理函數(shù)來解決僵尸進(jìn)程問題。 上一篇文章講解了pcntl_fork和pcntl_wait兩個(gè)函數(shù)的使用,本篇繼續(xù)講解PHP多進(jìn)程相關(guān)新知識(shí)。 僵尸(zombie)進(jìn)程 這里說下僵尸進(jìn)程...
摘要:消息隊(duì)列更常見的用途是主進(jìn)程分配任務(wù),子進(jìn)程消費(fèi)執(zhí)行。子進(jìn)程前面加了個(gè),這是為了防止父進(jìn)程還未往消息隊(duì)列中加入內(nèi)容直接退出。 前面幾節(jié)都是講解pcntl擴(kuò)展實(shí)現(xiàn)的多進(jìn)程程序。本節(jié)給大家介紹swoole擴(kuò)展的swoole_process模塊。 swoole多進(jìn)程 swoole_process 是swoole提供的進(jìn)程管理模塊,用來替代PHP的pcntl擴(kuò)展。 首先,確保安裝的swoole...
摘要:本節(jié)主要講解常用函數(shù)和進(jìn)程池的概念,也會(huì)涉及到守護(hù)進(jìn)程的知識(shí)。所以任何時(shí)候,建議預(yù)先創(chuàng)建好進(jìn)程,也就是使用進(jìn)程池的方式實(shí)現(xiàn)。 本節(jié)主要講解Posix常用函數(shù)和進(jìn)程池的概念,也會(huì)涉及到守護(hù)進(jìn)程的知識(shí)。本節(jié)難度較低。 Posix常用函數(shù) posix_kill 向指定pid進(jìn)程發(fā)送信號(hào)。成功時(shí)返回 TRUE , 或者在失敗時(shí)返回 FALSE 。 bool posix_kill ( int $...
摘要:本節(jié)講解幾個(gè)多進(jìn)程的實(shí)例。新開終端,我們使用命令查看進(jìn)程可以看到個(gè)進(jìn)程個(gè)主進(jìn)程,個(gè)子進(jìn)程。使用命令結(jié)束子進(jìn)程,主進(jìn)程會(huì)重新拉起一個(gè)新的子進(jìn)程。 本節(jié)講解幾個(gè)多進(jìn)程的實(shí)例。 多進(jìn)程實(shí)例 Master-Worker結(jié)構(gòu) 下面例子實(shí)現(xiàn)了簡(jiǎn)單的多進(jìn)程管理: 支持設(shè)置最大子進(jìn)程數(shù) Master-Worker結(jié)構(gòu):Worker掛掉,Master進(jìn)程會(huì)重新創(chuàng)建一個(gè)
摘要:修復(fù)添加超過萬個(gè)以上定時(shí)器時(shí)發(fā)生崩潰的問題增加模塊,下高性能序列化庫修復(fù)監(jiān)聽端口設(shè)置無效的問題等。線程來處理網(wǎng)絡(luò)事件輪詢,讀取數(shù)據(jù)。當(dāng)?shù)娜挝帐殖晒α艘院螅蛇@個(gè)線程將連接成功的消息告訴進(jìn)程,再由進(jìn)程轉(zhuǎn)交給進(jìn)程。此時(shí)進(jìn)程觸發(fā)事件。 本文示例代碼詳見:https://github.com/52fhy/swoo...。 簡(jiǎn)介 Swoole是一個(gè)PHP擴(kuò)展,提供了PHP語言的異步多線程服務(wù)器...
閱讀 2991·2021-11-25 09:43
閱讀 3636·2021-08-31 09:41
閱讀 1248·2019-08-30 15:56
閱讀 2136·2019-08-30 15:55
閱讀 2999·2019-08-30 13:48
閱讀 2821·2019-08-29 15:15
閱讀 989·2019-08-29 15:14
閱讀 2661·2019-08-28 18:26