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

OldBoy~發表於2018-02-02

先簡單來了解一下多程式 [來初步瞭解一下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

相關文章