PHP多程式學習(一)__來初步瞭解一下PHP多程式及簡單demo

OldBoy~發表於2018-01-30

php是一門單程式弱型別的語言,PHP處理多併發主要是依賴伺服器或PHP-FPM的多程式及它們程式的複用,多程式的作用優點大家可以去網上了解,PHP實現多程式在實際專案中意義也是不容小覷的。比如:日常任務中,有時需要通過php指令碼執行一些日誌分析,佇列處理等任務,當資料量比較大時,可以使用多程式來處理。

要實現PHP的多程式,需要用到函式pcntl_fork,那麼就需要開啟擴充套件 pcntl和 posix,在上一篇文章已經有安裝方法。

入門須知

  • 孤兒程式:一個父程式退出,而它的一個或多個子程式還在執行,那麼那些子程式將成為孤兒程式。孤兒程式將被init程式(程式號為1)所收養,並由init程式對它們完成狀態收集工作。
  • 殭屍程式:一個程式使用fork建立子程式,如果子程式退出,而父程式並沒有呼叫wait或waitpid獲取子程式的狀態資訊,那麼子程式的程式描述符仍然儲存在系統中。這種程式稱之為僵死程式。
  • 殭屍程式危害:如果程式不呼叫wait / waitpid的話, 那麼保留的那段資訊就不會釋放,其程式號就會一直被佔用,但是系統所能使用的程式號是有限的,如果大量的產生僵死程式,將因為沒有可用的程式號而導致系統不能產生新的程式. 此即為殭屍程式的危害,應當避免。任何一個子程式(init除外)在exit()之後,並非馬上就消失掉,而是留下一個稱為殭屍程式(Zombie)的資料結構,等待父程式處理。
  • 已經產生的殭屍程式,解決方法:kill掉父程式,它產生的僵死程式就變成了孤兒進 程,這些孤兒程式會被init程式接管,init程式會wait()這些孤兒程式,釋放它們佔用的系統程式表中的資源。

鳥哥語錄(多程式優點)http://www.laruence.com/2009/06/11/930.html

  • 使用多程式, 子程式結束以後, 核心會負責回收資源
  • 使用多程式,子程式異常退出不會導致整個程式Thread退出. 父程式還有機會重建流程.
  • 一個常駐主程式, 只負責任務分發, 邏輯更清楚.

切記!切記!切記!

  • PHP多程式一般應用在PHP_CLI命令列中執行php指令碼,不要在web訪問時使用。
  • 通過pcntl_XXX系列函式使用多程式功能。注意:pcntl_XXX只能執行在php CLI(命令列)環境下,在web伺服器環境下,會出現無法預期的結果,請慎用!
  • 鳥哥提醒:也就是說, 打消你在PHP Web開發中使用多程式的念頭吧!

建立子程式(pcntl_fork)

pcntl_fork() — 在當前程式當前位置產生分支(子程式)。此函式建立了一個新的子程式後,子程式會繼承父程式當前的上下文,和父程式一樣從pcntl_fork()函式處繼續向下執行,只是獲取到的pcntl_fork()的返回值不同,我們便能從判斷返回值來區分父程式和子程式,分配父程式和子程式去做不同的邏輯處理。
pcntl_fork()函式成功執行時會在父程式返回子程式的程式id(pid),因為系統的初始程式init程式的pid為1,後來產生程式的pid都會大於此程式,所以我們可以通過判斷pcntl_fork()的返回值大於1來確實當前程式是父程式;
而在子程式中,此函式的返回值會是固定值0,我們也可以通過判斷pcntl_fork()的返回值為0來確定子程式;
而pcntl_fork()函式在執行失敗時,會在父程式返回-1,當然也不會有子程式產生。

簡單demo

<?php
    $ppid = posix_getpid();
    $pid = pcntl_fork();
    if ($pid == -1) {
        echo 'fork子程式失敗!';
    } elseif ($pid > 0) {
        echo "我是父程式,我的程式id是{$ppid}.";
        echo "\r\n";
        sleep(20); // 保持20秒,確保能被ps查到
    }else{
        $cpid = posix_getpid();
        echo "我是{$ppid}的子程式,我的程式id是{$cpid}.";
        echo "\r\n";
        sleep(20); // 保持20秒,確保能被ps查到
    }
# php fork.php   //centos下執行命令
我是父程式,我的程式id是7625.
我是7625的子程式,我的程式id是7626.
# ps aux | grep fork.php  //centos下20秒內執行命令
root      7625  0.0  0.6 143892  6496 pts/1    S+   03:27   0:00 php fork.php
root      7626  0.0  0.4 143892  4252 pts/1    S+   03:27   0:00 php fork.php
root      7628  7.0  0.0 103268   860 pts/2    S+   03:27   0:00 grep fork.php

posix_getpid()函式作用是:獲取當前程式的pid;

進一步說明

上邊的程式碼如果建立子程式成功的話,系統就有了2個程式,一個為父程式,一個為子程式,子程式的id號為$pid。在系統執行到$pid = pcntl_fork();時,在這個地方進行分支,父子程式各自開始執行各自的程式程式碼。程式碼的執行結果是父程式那塊程式碼 和子程式的程式碼都走了,很奇怪吧,為什麼一個elseif和else互斥的程式碼中,都輸出了結果?其實是像上邊所說的,程式碼在pcntl_fork時,一個父程式執行父程式那塊程式碼,一個子程式執行了子程式那塊程式碼。在程式碼結果上就顯示了“我是父程式....”和"我是子程式..."。至於誰先誰後的問題,這得要看系統資源的分配了。

相關文章