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

PHP pcntl 多進程實戰:大量資料分批處理與主進程等待機制

     編輯:PHP 相關知識

PHP pcntl_fork() 實現多進程並行處理完整指南

PHP 預設單進程執行,面對百萬級資料處理時效能瓶頸明顯。pcntl 擴展提供 Unix 風格的進程控制,透過 pcntl_fork() 建立子進程並行處理,可大幅縮短執行時間。本文以 80 萬筆資料分 20 進程處理為例,詳細說明 Fork 機制、進程同步與錯誤處理。

核心代碼實作

<?php
$maxRecords = 800000;
$workerCount = 20;
$pids = [];

for ($i = 0; $i < $workerCount; $i++) {
    $pid = pcntl_fork();
    
    switch ($pid) {
        case -1:
            // Fork 失敗
            error_log("Fork 失敗: 第 {$i} 個進程");
            exit(1);
            
        case 0:
            // ===== 子進程邏輯 =====
            $startId = ($maxRecords / $workerCount) * $i + 1;
            $endId   = ($maxRecords / $workerCount) * ($i + 1);
            
            // 實際業務處理
            processBatch($startId, $endId);
            
            // 子進程必須主動退出,避免繼續執行父進程代碼
            exit(0);
            
        default:
            // ===== 父進程邏輯 =====
            $pids[$i] = $pid;
            break;
    }
}

// ===== 父進程:等待所有子進程結束 =====
foreach ($pids as $index => $pid) {
    if ($pid > 0) {
        // 等待特定 PID 結束,取得狀態碼
        pcntl_waitpid($pid, $status);
        
        // 檢查子進程退出狀態
        if (pcntl_wifexited($status)) {
            $exitCode = pcntl_wexitstatus($status);
            if ($exitCode !== 0) {
                error_log("子進程 {$index} (PID: {$pid}) 異常退出,代碼: {$exitCode}");
            }
        } elseif (pcntl_wifsignaled($status)) {
            $signal = pcntl_wtermsig($status);
            error_log("子進程 {$index} 被信號 {$signal} 終止");
        }
    }
}

echo "所有子進程處理完成\n";

function processBatch(int $start, int $end): void {
    // 實際資料庫查詢與處理邏輯
    // 範例:$pdo->query("SELECT * FROM big_table WHERE id BETWEEN $start AND $end");
    // 建議每個子進程建立獨立資料庫連線
}

關鍵概念解析

返回值進程角色說明
-1父進程Fork 失敗,資源不足或達進程上限
0子進程新建立的子進程,從 fork() 下一行開始執行
>0 (PID)父進程子進程的 Process ID,用於 waitpid 追蹤

最佳實踐與注意事項

  1. 資料庫連線隔離:每個子進程必須建立獨立 PDO/mysqli 連線,不可共享父進程連線
  2. 記憶體管理:子進程複製父進程記憶體 (Copy-on-Write),大量資料處理前釋放不需要的變數
  3. 信號處理:註冊 pcntl_signal(SIGTERM, ...) 優雅關閉
  4. 僵屍進程防範:必須呼叫 pcntl_wait() 或 pcntl_waitpid() 回收子進程
  5. Windows 不支援:pcntl 僅在 Linux/Unix/macOS 可用,Windows 需用 popen()、proc_open() 或佇列系統替代

進階:動態進程池模式

// 使用 pcntl_signal_dispatch() 處理信號
// 結合 Redis/RabbitMQ 實現任務佇列,Worker 持續消費任務
// 參考 Swoole Process、Symfony Messenger、Laravel Queue Worker 設計
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved