PHP多進程學習(二)__fork起多個子進程,父進程的阻塞與非阻塞


先簡單來了解一下多進程 [來初步了解一下PHP多進程及簡單demo]

php的多進程是不是可以無限制的fork子進程?
fork調用的一個奇妙之處就是它僅僅被調用一次,卻能夠返回兩次,它可能有三種不同的返回值:

  1. 在父進程中,fork返回新創建子進程的進程ID;
  2. 在子進程中,fork返回0;
  3. 如果出現錯誤,fork返回一個負值;

在fork函數執行完畢后,如果創建新進程成功,則出現兩個進程,一個是子進程,一個是父進程。在子進程中,fork函數返回0,在父進程中,fork返回新創建子進程的進程ID。我們可以通過fork返回的值來判斷當前進程是子進程還是父進程。
引用一位網友的話來解釋fpid的值為什么在父子進程中不同。“其實就相當於鏈表,進程形成了鏈表,父進程的fpid(p 意味point)指向子進程的進程id, 因為子進程沒有子進程,所以其fpid為0 

<?php //定義進程數量
define('FORK_NUMS', 5); //用於保存進程pid
$pids = array(); //我們創建5個子進程
for ($i = 0; $i < FORK_NUMS; ++$i) { $pids[$i] = pcntl_fork(); if ($pids[$i] == -1) { die('fork error'); } else if ($pids[$i]) { //這里是父進程空間,也就是主進程 //我們的for循環第一次進入到這里時,pcntl_wait會掛起當前主進程,等待第一個子進程執行完畢退出 //注意for循環的代碼是在主進程的,掛起主進程,相當於當前的for循環也阻塞在這里了 //第一個子進程退出后,然后再創建第二個子進程,到這里后又掛起,等待第二個子進程退出,繼續創建第三個,等等。。
 pcntl_wait($status); } else { //這里是子進程空間
        echo "父進程ID: ", posix_getppid(), " 進程ID : ", posix_getpid(), " {$i} \r\n"; //我們讓子進程等待3秒,再退出
        sleep(3); exit; } }

阻塞與非阻塞案例

通過pcntl_fork來創建子進程,使用pcntl_wait和pcntl_waitpid來回收子進程。子進程退出后,父進程沒有及時回收,就會產生僵屍進程。

[阻塞案例]

<?php define('FORK_NUMS', 5); $pids = array(); //創建5個子進程
for($i = 0; $i < FORK_NUMS; ++$i) { $pids[$i] = pcntl_fork(); if($pids[$i] == -1) { die('fork error'); } else if ($pids[$i]) { pcntl_wait($status); } else { echo getmypid() , " {$i} \r\n"; exit; } }
# php fork.php 52470 0 
52471 1 
52472 2 
52473 3 
52474 4 

以上代碼通過for循環fork出5個子進程,父進程會阻塞着等待子進程退出,然后創建下一個子進程。

---------------------BUG:創建多進程的目的,就是為了能夠並行的處理任務,阻塞的方式並不是我們期待的結果。------------------

[非阻塞案例]

<?php define('FORK_NUMS', 5); $pids = array(); //創建5個子進程
for($i = 0; $i < FORK_NUMS; ++$i) { $pids[$i] = pcntl_fork(); if($pids[$i] == -1) { die('fork error'); } else if ($pids[$i]) { pcntl_wait($status, WNOHANG); } else { echo getmypid() , " {$i} \r\n"; exit; } }
//反復執行幾次,發現沒有規律
[root@bogon default]# php fork.php 52645 0 
52647 2 
52646 1 
52648 3 
52649 4 [root@bogon default]# php fork.php 52660 0 
52663 3 
52664 4 
52661 1 
52662 2 [root@bogon default]# php fork.php 52681 0 
52683 2 
52685 4 
52684 3 
52682 1 

我們可以通過設置pcntl_wait的第二個參數為WNOHANG來控制進程是否阻塞。該函數可以在沒有子進程退出的情況下立刻跳出執行后續代碼。
pcntl_wait等同於以pid為-1調用pcntl_waitpid函數。
pcntl_waitpid函數可以等待指定pid的進程。

 

 

本文章參考的https://www.cnblogs.com/jkko123/p/6294602.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM