国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

用PHP玩轉進程之二 — 多進程PHPServer

stormjun / 1120人閱讀

摘要:代碼實現啟動啟動流程見流程,主要包括守護進程保存注冊信號處理器創建多進程這部分。模擬調度實際用實現捕獲信號其中,會在每次調度過程中,捕獲信號并執行注冊的信號處理器。

首發于 樊浩柏科學院

經過 用 PHP 玩轉進程之一 — 基礎 的回顧復習,我們已經掌握了進程的基礎知識,現在可以嘗試用 PHP 做一些簡單的進程控制和管理,來加深我們對進程的理解。接下來,我將用多進程模型實現一個簡單的 PHPServer,基于它你可以做任何事。

PHPServer 完整的源代碼,可前往 fan-haobai/php-server 獲取。

總流程

該 PHPServer 的 Master 和 Worker 進程主要控制流程,如下圖所示:

其中,主要涉及 3 個對象,分別為 入口腳本、Master 進程、Worker 進程。它們扮演的角色如下:

入口腳本:主要實現 PHPServer 的啟動、停止、重載功能,即觸發 Master 進程startstopreload流程;

Master 進程:負責創建并監控 Worker 進程。在啟動階段,會注冊信號處理器,然后創建 Worker;在運行階段,會持續監控 Worker 進程健康狀態,并接受來自入口腳本的控制信號并作出響應;在停止階段,會停止掉所有 Worker 進程;

Worker 進程:負責執行業務邏輯。在被 Master 進程創建后,就處于持續運行階段,會監聽到來自 Master 進程的信號,以實現自我的停止;

整個過程,又包括 4 個流程

流程 ① :以守護態啟動 PHPServer 時的主要流程。入口腳本會進行 daemonize,也就是實現進程的守護態,此時會fork出一個 Master 進程;Master 進程先經過 保存 PID、注冊信號處理器 操作,然后 創建 Worker 會fork出多個 Worker 進程;

流程 ② :為 Master 進程持續監控的流程,過程中會捕獲入口腳本發送來的信號。主要監控 Worker 進程健康狀態,當 Worker 進程異常退出時,會嘗試創建新的 Worker 進程以維持 Worker 進程數量;

流程 ③ :為 Worker 進程持續運行的流程,過程中會捕獲 Master 進程發送來的信號。流程 ① 中 Worker 進程被創建后,就會持續執行業務邏輯,并阻塞于此;

流程 ④ :停止 PHPServer 的主要流程。入口腳本首先會向 Master 進程發送 SIGINT 信號,Master 進程捕獲到該信號后,會向所有的 Worker 進程轉發 SIGINT 信號(通知所有的 Worker 進程終止),等待所有 Worker 進程終止退出;

在流程 ② 中,Worker 進程被 Master 進程fork出來后,就會 持續運行 并阻塞于此,只有 Master 進程才會繼續后續的流程。
代碼實現 啟動

啟動流程見 流程 ①,主要包括 守護進程、保存 PID、注冊信號處理器、創建多進程 Worker 這 4 部分。

守護進程

首先,在入口腳本中fork一個子進程,然后該進程退出,并設置新的子進程為會話組長,此時的這個子進程就會脫離當前終端的控制。如下圖所示:

這里使用了 2 次fork,所以最后fork的一個子進程才是 Master 進程,其實一次fork也是可以的。代碼如下:

protected static function daemonize()
{
    umask(0);
    $pid = pcntl_fork();
    if (-1 === $pid) {
        exit("process fork fail
");
    } elseif ($pid > 0) {
        exit(0);
    }

    // 將當前進程提升為會話leader
    if (-1 === posix_setsid()) {
        exit("process setsid fail
");
    }

    // 再次fork以避免SVR4這種系統終端再一次獲取到進程控制
    $pid = pcntl_fork();
    if (-1 === $pid) {
        exit("process fork fail
");
    } elseif (0 !== $pid) {
        exit(0);
    }
}
通常在啟動時增加-d參數,表示進程將運行于守護態模式。

當順利成為一個守護進程后,Master 進程已經脫離了終端控制,所以有必要關閉標準輸出和標準錯誤輸出。如下:

protected static function resetStdFd()
{
    global $STDERR, $STDOUT;
    //重定向標準輸出和錯誤輸出
    @fclose(STDOUT);
    fclose(STDERR);
    $STDOUT = fopen(static::$stdoutFile, "a");
    $STDERR = fopen(static::$stdoutFile, "a");
}
保存PID

為了實現 PHPServer 的重載或停止,我們需要將 Master 進程的 PID 保存于 PID 文件中,如php-server.pid文件。代碼如下:

protected static function saveMasterPid()
{
    // 保存pid以實現重載和停止
    static::$_masterPid = posix_getpid();
    if (false === file_put_contents(static::$pidFile, static::$_masterPid)) {
        exit("can not save pid to" . static::$pidFile . "
");
    }

    echo "PHPServer start