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

PHP 多線程實戰:pthreads 擴展安裝、Worker 模式與百度搜索併發抓取效能對比

     編輯:PHP 相關知識

為什麼 PHP 需要多線程?

  • I/O 密集型任務:並發 HTTP 請求、資料庫查詢、檔案讀寫
  • 單行程同步阻塞嚴重浪費 CPU 等待時間
  • Swoole/Workerman 是更好的長運行選擇,但 pthreads 適合 CLI 腳本快速並行化

編譯安裝 pthreads (Linux,PHP 7.x/8.x)

# 1. PHP 必須啟用 ZTS (Zend Thread Safety)
./configure --prefix=/usr/local/php \
    --enable-maintainer-zts \  # 關鍵!
    --with-config-file-path=/usr/local/php/etc \
    --enable-mbstring --with-curl --with-openssl \
    --enable-fpm --with-pdo-mysql
make && make install

# 2. 編譯 pthreads
git clone https://github.com/krakjoe/pthreads.git
cd pthreads
/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config
make && make install

# 3. 啟用擴展
echo "extension=pthreads.so" >> /usr/local/php/etc/php.ini

# 4. 驗證
php -m | grep pthreads
php -r "echo 'pthreads version: ' . phpversion('pthreads');"

核心類別速覽

類別用途
Thread繼承並實作 run(),啟動 start(),等待 join()
Worker可重用執行緒池,stack() 推入 Threaded 任務
PoolWorker 集合,submit() 任務自動分配
Threaded可跨執行緒共享的物件基類,支援同步鎖
VolatilePHP 7.2+ 新增,非不可變共享物件

實戰:併發抓取百度搜索 (100 次請求)

<?php
class HttpTask extends Thread
{
    public string $url;
    public string $result = '';
    public bool $error = false;

    public function __construct(string $url) { $this->url = $url; }

    public function run(): void
    {
        $ch = curl_init($this->url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => 5,
            CURLOPT_USERAGENT => 'Mozilla/5.0 (PHP pthreads)',
            CURLOPT_FOLLOWLOCATION => true,
        ]);
        $this->result = curl_exec($ch);
        $this->error = curl_errno($ch) > 0;
        curl_close($ch);
    }
}

function runConcurrent(array $urls): array
{
    $threads = [];
    foreach ($urls as $i => $url) {
        $threads[$i] = new HttpTask($url);
        $threads[$i]->start();
    }

    $results = [];
    foreach ($threads as $i => $thread) {
        $thread->join(); // 等待完成
        $results[$i] = [
            'url' => $thread->url,
            'success' => !$thread->error,
            'length' => strlen($thread->result),
        ];
    }
    return $results;
}

// 生成 100 個不同搜索關鍵詞
$urls = [];
for ($i = 0; $i < 100; $i++) {
    $urls[] = "https://www.baidu.com/s?wd=" . urlencode(mt_rand(10000, 20000));
}

// 多線程執行
$start = microtime(true);
$mtResult = runConcurrent($urls);
$mtTime = microtime(true) - $start;

// 同步迴圈執行
$start = microtime(true);
$syncResult = [];
foreach ($urls as $url) {
    $ch = curl_init($url);
    curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>5]);
    $syncResult[] = strlen(curl_exec($ch));
    curl_close($ch);
}
$syncTime = microtime(true) - $start;

echo "多線程: {$mtTime:.3f}s\n";
echo "同步迴圈: {$syncTime:.3f}s\n";
echo "加速比: " . ($syncTime / $mtTime) . "x\n";
/*
典型輸出:
多線程: 2.145s
同步迴圈: 18.732s
加速比: 8.73x
*/

Worker 模式優化(適用於大量短任務)

$pool = new Pool(20, HttpTask::class); // 20 個 Worker

foreach ($urls as $url) {
    $pool->submit(new HttpTask($url));
}

$pool->shutdown(); // 等待所有任務完成

$results = [];
while ($pool->collect()) {
    // 收集結果需自行在 Threaded 物件中保存
}

坑點與避雷指南

問題原因解決
Segmentation fault非 ZTS 構建、擴展版本不匹配重編譯 PHP + pthreads,版本嚴格對應
無法共享資源普通物件不可跨執行緒繼承 Threaded 或使用 Volatile
死鎖不當使用 synchronized盡量無鎖設計,用 Channel/Queue 傳遞數據
內存洩漏大量 Thread 物件未釋放用 Pool 復用 Worker,任務完成 unset
Windows 不支援pthreads 僅支援 POSIX 執行緒Windows 用併發進程 或 WSL2 / Docker

現代替代方案對比

方案模型適用場景學習曲線
pthreads多線程CLI 腳本快速並行低
Swoole協程 + 事件循環高併發 Server、WebSocket、常駐服務中
Workerman多進程 + 事件循環長連接、佇列消費、定時任務低
ReactPHP / AmpPromise + 事件循環非阻塞 I/O、微服務客戶端中
Guzzle PromisePromise僅 HTTP 併發請求極低

總結

pthreads 為 PHP CLI 腳本帶來真正的多線程能力,I/O 密集型任務可獲 5-10x 加速。但生產級長運行服務請選 **Swoole** 或 **Workerman**,生態更成熟、記憶體管理更安全。

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