首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 多進程程式設計實戰:從 fork 到訊號控制

     編輯:PHP 綜合知識

前言:為什麼需要多進程?

PHP 傳統上是單進程、同步阻塞的執行模型。面對高併發任務、長時間運行的背景作業或需並行處理的資料任務,多進程能顯著提升吞吐量。本文介紹基於 pcntl 擴展的多進程基礎:進程創建、任務分配、僵屍進程回收與訊號處理。

環境需求

  • Linux / BSD / Unix 系統(Windows 不支援 pcntl)
  • PHP 編譯時啟用 --enable-pcntl 且未禁用 posix
  • 執行 php -m 確認 pcntl 和 posix 已載入

核心概念:fork 與進程關係

pcntl_fork() 會創建子進程,父子進程代碼完全相同,唯一區別在於回傳值:

  • 父進程:回傳子進程 PID(>0)
  • 子進程:回傳 0
  • 失敗:回傳 -1
$pid = pcntl_fork();
if ($pid === -1) {
    die('fork failed');
} elseif ($pid === 0) {
    // 子進程邏輯
    echo "Child PID: " . getmypid() . PHP_EOL;
} else {
    // 父進程邏輯
    echo "Parent PID: " . getmypid() . ", Child PID: $pid" . PHP_EOL;
}

任務分配模式

透過 $pid 的不同值,在同一腳本中編寫父子進程各自的業務邏輯:

$parentPid = getmypid();
$pid = pcntl_fork();
if ($pid === 0) {
    // 子進程:執行耗時任務
    sleep(rand(10, 30));
    exit(0);
} else {
    // 父進程:繼續處理其他事務或等待子進程
}

僵屍進程與回收機制

子進程結束而父進程未回收時,會變成僵屍進程(STAT Z),佔用 PID 資源。兩種回收方式:

  1. 阻塞等待:pcntl_wait($status) 讓父進程掛起,直到有子進程結束。
  2. 訊號驅動:子進程結束時核心發送 SIGCHLD 給父進程,父進程在訊號處理器中呼叫 pcntl_wait()。
// 方式一:簡單阻塞
while (($pid = pcntl_wait($status)) > 0) {
    echo "Reaped child $pid" . PHP_EOL;
}

訊號處理:讓進程響應外部事件

註冊訊號處理器

function signalHandler($signo) {
    switch ($signo) {
        case SIGINT:
            echo "Caught SIGINT, shutting down..." . PHP_EOL;
            exit(0);
        case SIGCHLD:
            while (pcntl_wait($status) > 0) {}
            break;
    }
}
pcntl_signal(SIGINT, 'signalHandler');
pcntl_signal(SIGCHLD, 'signalHandler');

訊號分發機制

PHP 5.3+ 使用 pcntl_signal_dispatch() 主動檢查並分發訊號;舊版本需 declare(ticks=1)(效能較差)。長時間運行的循環中必須定期呼叫分發函數:

while (true) {
    // 業務邏輯
    pcntl_signal_dispatch(); // 處理待決訊號
    sleep(1);
}

進階:父進程管理子進程群

  • 父進程記錄所有子進程 PID
  • 接收 SIGTERM 時,遍歷發送 SIGTERM 給各子進程
  • 使用 posix_kill($pid, SIGTERM) 發送訊號
  • 守護進程模式:忽略 SIGHUP、脫離終端、重定向標準輸出

實戰練習建議

嘗試實作一個「進程池」:固定數量 Worker 進程,任務隊列分發,支援平滑重載(SIGUSR1 重讀配置)、優雅關閉(SIGTERM 完成當前任務後退出)、心跳監控。

總結

PHP 多進程雖不如 Go 或 Java 線程輕量,但透過 pcntl 仍能構建高效的並行處理系統。關鍵在於理解 fork 的複製語義、妥善處理僵屍進程、善用訊號機制進行進程間協作。生產環境建議搭配 Supervisor 或 Systemd 管理進程生命週期。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved