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

PHP 實現併發的三種方案:cURL 多執行柄、Stream Socket 非阻塞、PCNTL 多進程深度對比

     編輯:PHP 相關知識

方案一:cURL Multi 並發 HTTP 請求

核心代碼

function streamSocketConcurrent(array $targets, int $timeout = 10) {
    $sockets = [];
    $results = [];
    
    foreach ($targets as $key => $target) {
        $host = $target['host'];
        $port = $target['port'] ?? 80;
        $path = $target['path'] ?? '/';
        $method = $target['method'] ?? 'GET';
        $body = $target['body'] ?? '';
        $headers = $target['headers'] ?? [];
        
        $socket = stream_socket_client(
            "$host:$port", $errno, $errstr, $timeout,
            STREAM_CLIENT_ASYNC_CONNECT | STREAM_CLIENT_CONNECT
        );
        
        if (!$socket) {
            $results[$key] = ['error' => "Connect failed: $errstr ($errno)"];
            continue;
        }
        
        stream_set_blocking($socket, 0);  // 非阻塞
        stream_set_timeout($socket, $timeout);
        
        // 構建 HTTP 請求
        $req = "$method $path HTTP/1.1\r\nHost: $host\r\n";
        foreach ($headers as $h) $req .= "$h\r\n";
        if ($body) {
            $req .= "Content-Length: " . strlen($body) . "\r\n";
        }
        $req .= "Connection: close\r\n\r\n$body";
        
        fwrite($socket, $req);
        $sockets[$key] = $socket;
    }
    
    // 事件循環
    $read = $sockets;
    $write = $except = null;
    $start = microtime(true);
    
    while (count($read) > 0 && (microtime(true) - $start) < $timeout) {
        $rv = stream_select($read, $write, $except, 0, 200000);  // 200ms
        if ($rv === false) break;
        if ($rv === 0) continue;  // 超時繼續
        
        foreach ($read as $socket) {
            $key = array_search($socket, $sockets);
            $data = fread($socket, 8192);
            
            if (strlen($data) === 0) {
                // 連接關閉
                fclose($socket);
                unset($sockets[$key], $read[array_search($socket, $read)]);
            } else {
                $results[$key] = ($results[$key] ?? '') . $data;
            }
        }
        $read = array_values($sockets);  // 重置索引
    }
    
    // 清理剩餘
    foreach ($sockets as $socket) fclose($socket);
    
    return $results;
}

優缺點

優點缺點
底層 Socket 控制、無 cURL 開銷需手寫 HTTP 協議解析(Chunked、Gzip、重定向)
可用於任意 TCP 協議單進程、無法利用多核 CPU
內存佔用極低錯誤處理複雜、調試困難

方案三:PCNTL 多進程(真正並行)

核心代碼:Worker Pool 模式

 $i, 'data' => $i * 10]; }, range(1, 20));
$results = pcntlWorkerPool(function($task) {
    sleep(rand(1, 3));  // 模擬耗時任務
    return ['task_id' => $task['id'], 'result' => $task['data'] * 2];
}, $tasks, 4);

進階:共享內存 / 消息隊列替代文件

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