什麼是並行處理
當多個彼此不相依的處理(例如向多個外部 API 發出請求、資料庫的匯總處理等)依序執行時,總耗時等於各處理時間的加總。 若能同時執行,總耗時就能縮短為最耗時的那一項處理。 Laravel 的Concurrency Facade 以簡單的 API 實作這樣的並行執行。
Concurrency Facade 於 Laravel 11 中引入,Laravel 13 仍可繼續使用。
預設驅動使用子 PHP 程序,因此不需額外安裝套件即可運作。運作機制
Concurrency Facade 會將傳入的閉包序列化後,送至一個隱藏的 Artisan 指令,並以各自獨立的 PHP 程序執行它們。
處理完成後會將回傳值序列化後傳回父程序。
共提供三種驅動:
基本用法
Concurrency::run()
將閉包陣列傳入run() 方法後,即會並行執行。
回傳值會以陣列形式接收各閉包所回傳的結果。
指定驅動
若想使用特定驅動,可透過driver() 方法指定。
default 選項。
fork 驅動的用法
fork 驅動比 process 驅動更快,但只能在 PHP 的 CLI 環境(Artisan 指令或佇列 worker)中使用。
無法在 Web 請求中使用。
使用前請先安裝 spatie/fork 套件。
不接收執行結果:Concurrency::defer()
若你並不關心處理的結果,只希望在傳回 HTTP 回應之後,於背景執行,可以使用defer() 方法。
defer() 當下,閉包並不會立即執行。
它會在 HTTP 回應送出給使用者之後,並行地執行。
實戰範例:同時呼叫多個外部 API
想像一個電商網站的儀表板,需要從庫存管理 API、業績匯總 API、配送狀態 API 三處取得資訊。依序執行(改善前)
並行執行(改善後)
同時執行多個資料庫匯總
測試時的設定
測試環境中可使用sync 驅動,讓閉包依序執行。
沒有並行執行所需的程序啟動成本,能加速測試。
.env.testing 更改預設驅動。
注意事項
閉包的限制
閉包的限制
閉包會被序列化後傳給子程序。
無法從閉包外部捕獲不可序列化的物件(資料庫連線、檔案 handle、resource 等)。
需要的物件請在閉包內另行建立。
process 驅動的額外開銷
process 驅動的額外開銷
process 驅動有子程序啟動成本,因此當處理本身非常短(低於幾毫秒)時,並行執行未必更快。
對於 HTTP 請求或資料庫匯總等耗時超過 100ms 的處理,並行化才會顯現效果。fork 驅動的限制
fork 驅動的限制
fork 驅動會 fork PHP 程序,因此無法在 Web 請求(FPM 或 Apache)中使用。
僅能在 Artisan 指令或佇列 worker 中使用。例外的處理
例外的處理
若在並行執行過程中發生例外,
run() 會將例外重新拋出。
若希望即使個別處理發生例外,其他處理仍能繼續執行,請在閉包內使用 try/catch。下一步
佇列與工作
學習如何將處理透過佇列與工作,非同步地在背景執行