摘要:用于創(chuàng)建子進(jìn)程。該函數(shù)阻塞當(dāng)前進(jìn)程,只到當(dāng)前進(jìn)程的一個子進(jìn)程退出或者收到一個結(jié)束當(dāng)前進(jìn)程的信號。注意處需要注意子進(jìn)程需要防止子進(jìn)程也進(jìn)入循環(huán)。如果沒有,最終創(chuàng)建的子進(jìn)程不只個。
本系列文章將向大家講解pcntl_*系列函數(shù),從而更深入的理解進(jìn)程相關(guān)知識。
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 平臺上不可用。pcntl_fork
int pcntl_fork ( void )
用于創(chuàng)建子進(jìn)程。成功時,在父進(jìn)程執(zhí)行線程內(nèi)返回產(chǎn)生的子進(jìn)程的PID,在子進(jìn)程執(zhí)行線程內(nèi)返回0。失敗時,在父進(jìn)程上下文返回-1,不會創(chuàng)建子進(jìn)程,并且會引發(fā)一個PHP錯誤。
fork.php
命令行運(yùn)行:
$ php fork.php Parent process,pid 98, child pid 99 Child process,pid 99該例里父進(jìn)程還沒有來得及等子進(jìn)程運(yùn)行完畢就自動退出了,子進(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)程里也加個sleep(5),你會看到子進(jìn)程ppid本來是大于1的,后來就變成1了。
注:如果是docker環(huán)境,孤立進(jìn)程的ppid可能是0。pcntl_waitpcntl_wait()函數(shù)用來讓父進(jìn)程等待子進(jìn)程退出,默認(rèn)情況下會阻塞主進(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)程的一個子進(jìn)程退出或者收到一個結(jié)束當(dāng)前進(jìn)程的信號。
我們修改代碼:
此時再次運(yùn)行程序,父進(jìn)程就會一直等待子進(jìn)程運(yùn)行結(jié)束然后退出。
pcntl_waitpid()和pcntl_wait()功能相同。前者第一個參數(shù)支持指定pid參數(shù),當(dāng)指定-1作為pid的值等同于后者。int pcntl_waitpid ( int $pid , int &$status [, int $options = 0 ] )當(dāng)已知子進(jìn)程pid的時候,可以使用pcntl_waitpid()。這兩個函數(shù)返回退出的子進(jìn)程進(jìn)程號(>1),發(fā)生錯誤時返回-1,如果提供了 WNOHANG 作為option(wait3可用的系統(tǒng))并且沒有可用子進(jìn)程時返回0。
返回值為退出的子進(jìn)程進(jìn)程號時,想了解如何退出,可以通過 $status狀態(tài)碼反應(yīng)。
非阻塞模式pcntl_wait()默認(rèn)情況下會阻塞主進(jìn)程,直到子進(jìn)程執(zhí)行完畢才繼續(xù)往下運(yùn)行。如果設(shè)置最后一個參數(shù)為常量WNOHANG,那么就不會阻塞主進(jìn)程,而是繼續(xù)執(zhí)行后續(xù)代碼, 此時 pcntl_waitpid 就會返回0。
示例:
0){ sleep(10);//此處為了方便看效果,實(shí)際不需要 break; } } }else{ $id = getmypid(); echo "Child process,pid {$id} "; sleep(2); }該示例里只有一個子進(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號進(jìn)程運(yùn)行時間最短,但是是最后回收。我們再加上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ù)的時候,里面的代碼是不會運(yùn)行的。
注意:#2處需要注意子進(jìn)程需要exit,防止子進(jìn)程也進(jìn)入for循環(huán)。如果沒有exit(),最終創(chuàng)建的子進(jìn)程不只3個。
檢測status函數(shù)在 pcntl_wait和pcntl_waitpid兩個函數(shù)中的$status中存了子進(jìn)程的狀態(tài)信息,這個參數(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)){ //不是通過接受信號中斷 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ā)布于公眾號飛鴻影的博客(fhyblog)及博客園,轉(zhuǎn)載需作者同意。
歡迎關(guān)注公眾號及時獲取最新文章推送!
推薦!每月僅需$2.5,即可擁有配置SSD的VPS!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/28874.html
摘要:任何進(jìn)程在退出前使用退出都會變成僵尸進(jìn)程用于保存進(jìn)程的狀態(tài)等信息,然后由進(jìn)程接管。這時候就算手動結(jié)束腳本程序也無法關(guān)閉這個僵尸子進(jìn)程了。那么子進(jìn)程結(jié)束后,沒有回收,就產(chǎn)生僵尸進(jìn)程了。本小節(jié)我們通過安裝信號處理函數(shù)來解決僵尸進(jìn)程問題。 上一篇文章講解了pcntl_fork和pcntl_wait兩個函數(shù)的使用,本篇繼續(xù)講解PHP多進(jìn)程相關(guān)新知識。 僵尸(zombie)進(jìn)程 這里說下僵尸進(jìn)程...
摘要:消息隊(duì)列更常見的用途是主進(jìn)程分配任務(wù),子進(jìn)程消費(fèi)執(zhí)行。子進(jìn)程前面加了個,這是為了防止父進(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)程池的概念,也會涉及到守護(hù)進(jìn)程的知識。所以任何時候,建議預(yù)先創(chuàng)建好進(jìn)程,也就是使用進(jìn)程池的方式實(shí)現(xiàn)。 本節(jié)主要講解Posix常用函數(shù)和進(jìn)程池的概念,也會涉及到守護(hù)進(jìn)程的知識。本節(jié)難度較低。 Posix常用函數(shù) posix_kill 向指定pid進(jìn)程發(fā)送信號。成功時返回 TRUE , 或者在失敗時返回 FALSE 。 bool posix_kill ( int $...
摘要:本節(jié)講解幾個多進(jìn)程的實(shí)例。新開終端,我們使用命令查看進(jìn)程可以看到個進(jìn)程個主進(jìn)程,個子進(jìn)程。使用命令結(jié)束子進(jìn)程,主進(jìn)程會重新拉起一個新的子進(jìn)程。 本節(jié)講解幾個多進(jìn)程的實(shí)例。 多進(jìn)程實(shí)例 Master-Worker結(jié)構(gòu) 下面例子實(shí)現(xiàn)了簡單的多進(jìn)程管理: 支持設(shè)置最大子進(jìn)程數(shù) Master-Worker結(jié)構(gòu):Worker掛掉,Master進(jìn)程會重新創(chuàng)建一個
摘要:修復(fù)添加超過萬個以上定時器時發(fā)生崩潰的問題增加模塊,下高性能序列化庫修復(fù)監(jiān)聽端口設(shè)置無效的問題等。線程來處理網(wǎng)絡(luò)事件輪詢,讀取數(shù)據(jù)。當(dāng)?shù)娜挝帐殖晒α艘院?,由這個線程將連接成功的消息告訴進(jìn)程,再由進(jìn)程轉(zhuǎn)交給進(jìn)程。此時進(jìn)程觸發(fā)事件。 本文示例代碼詳見:https://github.com/52fhy/swoo...。 簡介 Swoole是一個PHP擴(kuò)展,提供了PHP語言的異步多線程服務(wù)器...
閱讀 2995·2021-11-25 09:43
閱讀 3639·2021-08-31 09:41
閱讀 1255·2019-08-30 15:56
閱讀 2145·2019-08-30 15:55
閱讀 3006·2019-08-30 13:48
閱讀 2823·2019-08-29 15:15
閱讀 994·2019-08-29 15:14
閱讀 2664·2019-08-28 18:26