網頁

2008年1月25日 星期五

利用PHP寫Multi Process程式 1 - 產生子程序

利用PHP寫Multi Process程式

別問我怎麼會搞到要用 PHP 來寫 multi-process 程式,偏偏最近的案子裡就是有這種需要,不然我也是千百萬個不願意這樣寫…既然資料已經查了一堆,就寫出來給大家看吧。
PS: 預設讀者已知什麼是 multi-process programming ,並且什麼是 pid 。

1.1 產生子程序

1.1.1 產生一個子程序

在PHP裡沒有支援多執行緒編程 (multi-threaded programming) ,因此需要寫類似的功能就必須採取多程序編程 (multi-process programming) 的方式。一般在 unix-like 的作業系統下,要寫多程序程式一定會用到fork。在 PHP 裡也不例外。若要在 PHP 中建一個子程序,要叫用 pcntl_fork()函式。以下是一個簡單的程式樣版:

樣版

<?php
$pid = pcntl_fork(); //在這裡開始產生程式的分岔
if ($pid == -1) {
     die('無法產生子程序');
} else if ($pid) {
     // 父程序會進入這裡
} else {
     // 子程序會進入這裡
}
?>
  • 子程序的 $pid 會是 0
  • 父程序會拿到子程序的 $pid 編號。
  • pcntl_fork() 函數目前只能在 Unix-like 的作業系統下使用(精確的說是有 System V API 的作業系統), PHP 目前沒有實作 Windows 環境下的版本。
  • 有關 PHP 裡多程序的其它資料都在 PHP 官方網站上可以找得到。

1.1.2 產生多個子程序

以下這程式會造出多個子程序,子程序造出後父程序會等子程序全都離開後才離開。

範例

<?php
$process_num = 5;
print "老爸:我是老爸,我要生{$process_num}個小孩。\n";
$children = array();

for($i = 1;$i <= $process_num; $i++) {
    $pid = pcntl_fork();
    if($pid == -1) {
        exit(1);
    } else if ($pid) {
    /*這是老爸專區*/
    $children[] = $pid; //紀錄下每個孩子的編號
    print "老爸:生了一個第{$i}個孩子,pid是{$pid}\n";
   } else {
   /*這是小朋友區*/
    break; //直接出迴圈
   }
}
if($pid) { /* 老爸會在這裡休息 */
    $status = null;
    /********************************************************
     * 下面這行的存在意義是:
     *  就算是等所有孩子先行離開以後
     *  父程序才開始等子程序
     *  父程序仍然會知道子程序已離開
     **********************************************************/
    sleep(8); 
    foreach($children as $pid) { //要等每個孩子都離開才離開
        pcntl_waitpid($pid, $status); 
        print "老爸:pid是{$pid}的那個孩子,回去時他告訴我他的狀況是{$status}\n";
    }
    print '老爸也要走了'."\n";
} else {
    /*以下是小朋友遊樂區*/
    print "我是第{$i}個小朋友,我要睡{$i}秒\n";
    sleep($i);
    print "我是第{$i}個小朋友,要走了\n";
    exit(0);
}
?>

解說

  • 在此程式用到了 pcntl_waitpid() ,其參數是子程序的 $pid ,程式執行到此函式時,父行程會等到指定的子程序結束以後才繼續動作。

執行結果

老爸:我是老爸,我要生5個小孩。
我是第1個小朋友,我要睡1秒
老爸:生了一個第1個孩子,pid是10487
我是第2個小朋友,我要睡2秒
老爸:生了一個第2個孩子,pid是10488
我是第3個小朋友,我要睡3秒
老爸:生了一個第3個孩子,pid是10489
我是第4個小朋友,我要睡4秒
老爸:生了一個第4個孩子,pid是10490
我是第5個小朋友,我要睡5秒
老爸:生了一個第5個孩子,pid是10491
我是第1個小朋友,要走了
我是第2個小朋友,要走了
我是第3個小朋友,要走了
我是第4個小朋友,要走了
我是第5個小朋友,要走了
老爸:pid是10487的那個孩子,回去時他告訴我他的狀況是0
老爸:pid是10488的那個孩子,回去時他告訴我他的狀況是0
老爸:pid是10489的那個孩子,回去時他告訴我他的狀況是0
老爸:pid是10490的那個孩子,回去時他告訴我他的狀況是0
老爸:pid是10491的那個孩子,回去時他告訴我他的狀況是0
老爸也要走了

6 則留言:

spw 提到...

感謝您的分享 :)
舉例易懂且有趣

Vincent 提到...

您好,想請教如果在子程式裡做運算,如何回傳到父程序,謝謝。

Unknown 提到...

很棒的範例與解釋,十分感謝!

Unknown 提到...

淺顯易懂 謝謝分享:)

123 提到...

這篇寫的真牛,其他的我都看不董,淺顯易懂科普文

多采多姿 提到...

十幾年前的文章,還有人看,真是感動...