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