什么是并发处理
对多个外部 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 中修改默认驱动。
注意事项
闭包的限制
闭包的限制
闭包会被序列化传给子进程。
不能从闭包外部捕获无法序列化的对象(数据库连接、文件句柄、资源等)。
需要的对象请在闭包内部重新创建。
process 驱动的开销
process 驱动的开销
process 驱动需要启动子进程,因此如果处理本身非常短(几毫秒以内),并行执行未必更快。
HTTP 请求、数据库聚合等耗时 100ms 以上的处理,通过并行化才能真正体现出效果。fork 驱动的限制
fork 驱动的限制
fork 驱动会 fork PHP 进程,因此无法在 Web 请求(FPM 或 Apache)中使用。
请只在 Artisan 命令或队列 worker 中使用它。异常的处理
异常的处理
并行执行中若发生异常,
run() 会将异常重新抛出。
如果希望某个任务出错时其他任务仍能继续执行,请在闭包内使用 try/catch。下一步
队列与任务
了解如何使用队列与任务在后台异步执行处理