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

PHP CLI 模式下多進程應用實作:解決長駐腳本記憶體洩漏與異常中斷問題

     編輯:PHP 相關知識

PHP 並非為長駐行程設計,缺乏專用 GC 機制與有效記憶體管理,長時間運行易導致記憶體耗盡中斷。本文示範使用 pcntl 與 posix 擴展實作多進程架構,主進程負責任務分發,子進程執行具體邏輯並自動釋放資源。

多進程架構優勢

優勢說明
自動資源回收子進程結束時,核心自動回收記憶體、檔案控制代碼等資源
故障隔離子進程異常退出不影響主進程,主進程可重建任務流程
邏輯清晰主進程專注調度,子進程專注業務,職責分離

完整實作程式碼

<?php
#!/usr/bin/env php
/**
 * PHP 多進程命令解析器範例
 * @filename fork.php
 * @author Laruence
 * @license PHP License 3.0
 */

// 僅允許 CLI 模式執行
if (substr(php_sapi_name(), 0, 3) !== 'cli') {
    die("This program can only be run in CLI mode\n");
}

// 移除執行時間限制(CLI 預設無限制,保險起見)
set_time_limit(0);

$pid = posix_getpid();
$user = posix_getlogin();

echo <<

關鍵函數說明

  • pcntl_fork():建立子進程,父進程回傳子進程 PID,子進程回傳 0
  • pcntl_wait($status, WUNTRACED):阻塞等待子進程狀態變化
  • pcntl_wifexited() / pcntl_wexitstatus():判斷正常退出並獲取退出碼
  • pcntl_wifsignaled() / pcntl_wtermsig():判斷信號終止並獲取信號編號
  • posix_getpid() / posix_getlogin():獲取進程 ID 與登入用戶
  • readline() / readline_add_history():互動式命令列輸入與歷史記錄

生產環境改良方向

<?php
// 生產級任務佇列雛形
class TaskWorker {
    private $max_workers = 5;
    private $running = [];
    private $task_queue = [];
    
    public function addTask(callable $task) {
        $this->task_queue[] = $task;
    }
    
    public function run() {
        while (!empty($this->task_queue) || !empty($this->running)) {
            // 回收結束的子進程
            foreach ($this->running as $pid => $info) {
                $status = 0;
                $result = pcntl_waitpid($pid, $status, WNOHANG);
                if ($result > 0) {
                    unset($this->running[$pid]);
                    // 處理結果、記錄日誌...
                }
            }
            
            // 啟動新任務
            while (count($this->running) < $this->max_workers && !empty($this->task_queue)) {
                $task = array_shift($this->task_queue);
                $pid = pcntl_fork();
                if ($pid == 0) {
                    // 子進程執行任務
                    try {
                        $task();
                        exit(0);
                    } catch (Throwable $e) {
                        error_log($e->getMessage());
                        exit(1);
                    }
                } elseif ($pid > 0) {
                    $this->running[$pid] = ['start' => microtime(true)];
                }
            }
            
            usleep(100000);  // 避免忙等待
        }
    }
}

重要安全警示

⚠️ 絕對不要在生產環境直接使用 eval() 執行外部輸入! 本範例僅供學習 pcntl 多進程機制。實際應用應將任務封裝為獨立腳本或類方法,透過參數傳遞而非代碼注入執行。

適用場景

  • CLI 批次處理任務(匯入/匯出、報表產生)
  • 長時間運行的守護行程
  • 需隔離記憶體的並發任務處理
  • 第三方 API 批量請求(避免單一進程記憶體累積)

環境需求

  • PHP 編譯時需啟用 --enable-pcntl 與 --enable-posix
  • Windows 環境不支援 pcntl,需使用 pthreads 或改用進程管理工具(如 Supervisor)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved