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

PHP 實現非同步請求的三種主流方法比較

     編輯:PHP 相關知識

為什麼需要非同步請求

PHP 原生不支援多執行緒,所有程式碼預設同步阻塞執行。當需要發送郵件、呼叫外部 API、處理影片轉碼等耗時任務時,若同步等待回應,會嚴重拖慢使用者回應速度。非同步請求讓主流程「發送後即忘記」,背景任務獨立執行,大幅提升吞吐量與使用者體驗。

方法一:cURL 多執行緒模擬(最常用)

利用 curl_multi_* 系列函數並行發送多個 HTTP 請求,或設定極短逾時達成「發射後不理」效果。

<?php
// 發射後不理:設定 1 秒逾時,主程式不等待回應
$ch = curl_init('https://api.example.com/notify');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => http_build_query(['event' => 'order_created']),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 1,       // 最小 1 秒
    CURLOPT_NOSIGNAL       => true,    // 避免信號干擾
]);
curl_exec($ch); // 1 秒後繼續,無論回應與否
curl_close($ch);

// 後續主程式邏輯繼續執行...
echo '訂單建立成功,通知已發送';
?>

優點: 相容性好、支援完整 HTTP 協定、可攜帶複雜 Header/Body。
缺點: 最小逾時 1 秒仍有阻塞、大量併發易耗盡連線資源、無法獲取執行結果。

方法二:popen() 執行背景程序

開啟一個指向命令的管道,啟動獨立 PHP 進程處理背景任務。

<?php
// 背景執行獨立腳本,主程式立即繼續
$cmd = '/usr/bin/php /var/www/tasks/send_email.php ' . escapeshellarg($userId) . ' > /dev/null 2>&1 &';
pclose(popen($cmd, 'r'));

// 主程式繼續...
echo '註冊成功,歡迎信已排程發送';
?>

優點: 真正非阻塞、可執行任意 CLI 指令、不受 HTTP 逾時限制。
缺點: 單向管道(無法讀取輸出)、高併發產生大量進程拖垮系統、需妥善管理進程生命週期、Windows 相容性較差。

方法三:fsockopen() 底層 Socket 非阻塞

手動組裝 HTTP Request 透過 TCP 連線發送,設定非阻塞模式立即返回。

<?php
$host = 'api.example.com';
$path = '/webhook';
$data = json_encode(['event' => 'payment_success']);

$fp = fsockopen($host, 80, $errno, $errstr, 2);
if ($fp) {
    stream_set_blocking($fp, 0); // 關鍵:非阻塞模式

    $request = "POST $path HTTP/1.1\r\n";
    $request .= "Host: $host\r\n";
    $request .= "Content-Type: application/json\r\n";
    $request .= "Content-Length: " . strlen($data) . "\r\n";
    $request .= "Connection: Close\r\n\r\n";
    $request .= $data;

    fwrite($fp, $request);
    fclose($fp); // 立即關閉,不讀取回應
} else {
    error_log("Socket 連線失敗: $errstr ($errno)");
}
?>

優點: 極低延遲、無外部依賴、完全控制協定細節。
缺點: 需手動處理 HTTP 協定細節(Chunked、Redirect、SSL 等)、錯誤處理複雜、HTTPS 需額外啟用 ssl:// 封裝協定與憑證驗證。

現代替代方案:訊息佇列(強烈推薦)

上述三種方法屬於「應用層臨時方案」,生產環境高併發場景建議引入訊息佇列:

  • Redis Lists / Streams:輕量、內建阻塞式讀取、支援消費者群組。
  • RabbitMQ:成熟 AMQP 實作、支援複雜路由、死信佇列、延遲佇列。
  • Kafka:高吞吐、持久化日誌、適合事件溯源與大數據管線。
  • Laravel Queue / Symfony Messenger:框架整合抽象層,支援多種驅動(Redis、Database、SQS、Beanstalkd)。
<?php
// Laravel Queue 範例
use App\Jobs\SendWelcomeEmail;

Route::post('/register', function () {
    // ... 驗證與建立使用者 ...
    SendWelcomeEmail::dispatch($user); // 丟入佇列,立即返回回應
    return response()->json(['message' => '註冊成功']);
});
?>

選擇指南

場景推薦方案理由
簡單通知、Webhook、低併發cURL 短逾時零依賴、快速上線
定時任務、影片轉碼、大量運算popen() + CLI 腳本脫離 Web 進程、無執行時間限制
極高併發、微服務內部通訊fsockopen / Swoole / RoadRunner繞過 HTTP 封裝開銷、支援協程
生產系統核心業務流程訊息佇列 (Redis/RabbitMQ/Kafka)可靠性、可觀測性、重試機制、擴展性

總結

PHP 雖無原生多執行緒,但透過 cURL、popen、fsockopen 等方式可模擬非同步行為。隨著業務增長,務必盡早遷移至訊息佇列架構,將「發送任務」與「執行任務」徹底解耦,構建高可用、可擴展的系統。

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