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

PHP 使用 pcntl_fork 實作多進程圖片下載器

     編輯:PHP 相關知識

PHP 使用 pcntl_fork 實作多進程圖片下載器

在處理大量圖片下載任務時,單進程循序執行效率極低。本文介紹如何使用 PHP 的 pcntl_fork 函數建立多進程,實現圖片並發下載,大幅提升下載速度。

環境需求與安裝

注意:pcntl 擴展僅支援 Linux/Unix 系統,Windows 環境無法直接使用。安裝步驟如下:

# 建立工作目錄並下載 PHP 原始碼
mkdir php && cd php
apt-get source php5
cd php5-*/ext/pcntl

# 編譯安裝擴展
phpize
./configure
make
make install

編譯成功後,會在 PHP 擴展目錄(通常為 /usr/lib/php/modules/)產生 pcntl.so,需在 php.ini 中加入 extension=pcntl.so 並重啟 PHP-FPM 或 Apache。

pcntl_fork 核心機制

pcntl_fork() 會在當前進程位置建立子進程。呼叫後:

  • 父進程:回傳子進程的 PID(正整數)
  • 子進程:回傳 0
  • 建立失敗:回傳 -1

父子進程從 fork 點繼續向下執行,各自擁有獨立的記憶體空間。

多進程下載實作範例

<?php
#!/usr/bin/php
// 目標網頁
$url = 'https://www.example.com';
$content = file_get_contents($url);

// 解析所有圖片連結
preg_match_all('/<img\s+src=["\'](.*?)["\']/', $content, $matches, PREG_SET_ORDER);
echo "已發現 " . count($matches) . " 張圖片\n";

$start = microtime(true);

foreach ($matches as $k => $val) {
    $pid[$k] = pcntl_fork();

    if ($pid[$k] == -1) {
        echo "建立子進程失敗\n";
        exit(-1);
    } elseif ($pid[$k]) {
        // 父進程:非阻塞等待子進程結束,避免殭屍進程
        pcntl_wait($status, WNOHANG);
    } else {
        // 子進程:執行下載任務
        download($url, $val);
        exit(0); // 子進程必須退出,否則會繼續 fork
    }
}

echo "下載完成\n";
echo "總耗時:" . (microtime(true) - $start) . " 秒\n";

function download($baseUrl, $match) {
    $picUrl = $match[1];

    // 處理相對路徑
    if (strpos($picUrl, '//') === false) {
        if (preg_match('@^(.*?)/@', $picUrl, $inner) == 0) {
            $picUrl = $baseUrl . $picUrl;
        } elseif (preg_match('@[:.]@', $inner[1]) == 0) {
            $picUrl = $baseUrl . $picUrl;
        }
    }

    $pic = @file_get_contents($picUrl);
    if ($pic === false) return;

    // 取得檔名並儲存
    preg_match('@/([^/]+)$@', $picUrl, $tmp);
    $filename = $tmp[1];
    $fp = fopen("tmp/" . $filename, "wb");
    fwrite($fp, $pic);
    fclose($fp);
}
?>

關鍵點說明

  1. 子進程必須 exit(0):否則子進程會繼續執行外層迴圈,導致遞迴式 fork,產生指數級進程爆炸
  2. 父進程使用 pcntl_wait($status, WNOHANG):非阻塞回收子進程,防止殭屍進程累積
  3. 錯誤處理:file_get_contents 失敗時靜默返回,避免單張圖片錯誤影響整體
  4. 目錄權限:確保 tmp/ 目錄存在且可寫入

效能對比

測試下載 20 張圖片:

  • 單進程循序下載:約 45 秒
  • 多進程並發下載:約 8 秒

速度提升約 5-6 倍,隨著圖片數量增加優勢更明顯。

希望本文對您的 PHP 多進程程式設計有所幫助。

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