短文2:用 pcntl_fock 函式淺談多程式怎麼回事

php_yt發表於2020-12-29

首先 pcntl 是 php 的擴充套件,其中 pcntl_fork() 是建立程式函式,檢視 php 手冊,pcntl 是 程式控制擴充套件

大多數對這塊還是比較陌生的,和開發沒啥關係吧,的確,是沒啥太大關係的。
ps -ef | grep php 或者 pstree -apn | grep php 想必一般都用過,列印出來的是這樣的:

ps -ef

上圖中一個 master程式下面並列兩個分支,就是子程式了。

使用過 workman 的也很熟悉上面的結構,workman 底層是 php 寫的,依賴於 php 擴充套件,其中 pcntl 就是其中之一很重要的依賴擴充套件,它的 master worker 結構就是這個擴充套件實現的。

迴歸正題,使用 pcntl_fork() 實現一下,fork 翻譯為 “分叉”,fork 一個子程式 即建立一個子程式。

<?php
$pid = pcntl_fork();
//父程式和子程式都會執行下面程式碼
if ($pid == -1) {
    //錯誤處理:建立子程式失敗時返回-1.
     die('could not fork');
} else if ($pid) {
     //父程式會得到子程式號,所以這裡是父程式執行的邏輯
     pcntl_wait($status); //等待子程式中斷,防止子程式成為殭屍程式。
} else {
     //子程式得到的$pid為0, 所以這裡是子程式執行的邏輯。
}

這段程式碼是官方示例程式碼,具體過程是執行到 pcntl_fork() 時 “拷貝” 一份原檔案(程式碼是一模一樣的哦)

用 pcntl_fock 函式淺談多程式怎麼回事

也就是說 pcntl_fork(); 的一霎那,之後的程式碼同時在兩個程式裡執行(包括給 $pid 賦值),所以 $pid 在兩個程式裡的賦值是不一樣的,在父程式裡返回的 $pid 大於 0,等於子程式的程式 id,通常叫做 pid (process id)。而子程式裡返回的 $pid 為 0。

所以通過 if 判斷,就區分開了哪個程式碼塊裡應該執行哪個角色的邏輯。master-worker 模型,一般master負責管理子程式數量等、處理訊號啥的,不處理業務邏輯,而 worker程式,顧名思義,工作程式。

<?php
$pid = pcntl_fork();
if ($pid == -1) {
     die('could not fork');
} else if ($pid) {
     // 父程式執行程式碼塊
     $master_pid = posix_getpid(); //獲得當前程式的 pid
     $worker_pids[] = $pid; // 收集子程式 pid
     echo "master_pid:".$master_pid.EOL;
     var_dump($worker_pids);

     pcntl_wait($status); //等待子程式中斷,防止子程式成為殭屍程式。
     echo PHP_EOL.'等待了10秒後..status:'.$status;
} else {
     // 子程式得到的$pid為0, 所以這裡是子程式執行的邏輯。
     // 幹活
     //為了不讓程式過早退出 我們 sleep 一下
     sleep(10);
}

類似於 nginx 的程式結構出來了

用 pcntl_fock 函式淺談多程式怎麼回事

用 pcntl_fock 函式淺談多程式怎麼回事

pcntl_wait($status); 是防止子程式成為殭屍程式的函式,是阻塞的,類似監聽。也就是當子程式執行完退出時,或者主動 exit() 時,父程式將捕獲狀態碼賦予 $status ,並且清理子程式。

最後一個點,前面提到:執行到 pcntl_fork() 時 “拷貝” 一份原檔案。注意的一點是,子程式繼承了父程式的變數和方法,但由於是兩個程式(兩個指令碼), 在子程式中給變數重新賦值,不會影響父程式裡的變數值,程式之間是隔離的。

<?php
$i = 1;
$pid = pcntl_fork();
if ($pid == -1) {
     die('could not fork');
} else if ($pid) {
    // 父程式
    echo '我是父程式:'.$i.PHP_EOL;
} else {
    // 子程式賦值
     $i = 2;
     sleep(1);
     echo '我是子程式:'.$i.PHP_EOL;
}
echo '兩個程式都會執行:'.$i.PHP_EOL;

執行下

用 pcntl_fock 函式淺談多程式怎麼回事

可以看到先列印出來的 1 是父程式輸出的,後面的 2 是子程式輸出的。

本作品採用《CC 協議》,轉載必須註明作者和本文連結
focus

相關文章