php框架需启用swoole协程环境(swoole_runtime::enablecoroutine(swoole_hook_all)并用coroutine::run包裹逻辑)才能实现真正异步io,否则http、数据库、文件等操作仍阻塞;laravel/symfony中须分别使用swoole协程客户端或amp promise解耦io,队列任务需在coroutine::run内执行协程io。

PHP框架在处理HTTP请求时,常因数据库查询、API调用、文件读写等IO操作陷入长时间等待,导致并发能力骤降、响应延迟飙升;不改造IO等待逻辑,再好的业务代码也跑不出高吞吐。
启用Swoole协程运行时(Laravel/Symfony通用前提)
所有基于Swoole的异步IO必须先激活协程环境,否则file_get_contents、curl_exec等函数仍走同步阻塞路径。
在框架启动入口(如public/index.php或bin/console顶部)插入以下两行:
swoole_runtime::enableCoroutine(SWOOLE_HOOK_ALL);
Swoole\Coroutine\run(function () { /* 框架启动逻辑 */ });
【SWOOLE_HOOK_ALL必须启用,漏掉FILE或CURL会导致部分IO仍阻塞】
这一步不做,后续所有“异步”操作都会退化为同步——你看到的并发只是假象。
Laravel中用协程并发调用多个API
传统Http::get()是同步阻塞的,每次调用都卡住整个请求生命周期;改用Swoole协程客户端可实现真正并行。
方法一:原生Swoole协程HTTP客户端(零依赖,性能最优)
在控制器中写:
go(function () {
$client = new Swoole\Coroutine\Http\Client('api.example.com', 443, true);
$client->set(['timeout' => 8]);
$client->get('/v1/users');
$this->userRes = $client->body;
});
go(function () {
$client = new Swoole\Coroutine\Http\Client('api.example.com', 443, true);
$client->set(['timeout' => 8]);
$client->get('/v1/orders');
$this->orderRes = $client->body;
});
注意:两个go()必须在同一协程作用域内发起,不能放在循环里无限制创建——协程开销虽小,但失控会耗尽栈内存。
Symfony中用Amp实现异步日志写入
当用户提交表单后需记录审计日志,又不想让HTTP响应被磁盘IO拖慢,可用Amp的Promise链解耦。
第一步:安装Amp组件
composer require amphp/amp amphp/file
第二步:在Controller中构造非阻塞写入流程
$logPath = '/var/log/app/activity.log';
$content = sprintf("[%s] %s\n", date('c'), $request->getClientIp());
Amp\File\write($logPath, $content, FILE_APPEND | LOCK_EX)
->onResolve(function (?Throwable $error) use ($response) {
if ($error === null) {
$response->headers->set('X-Log-Status', 'queued');
} else {
// 错误仅记监控,不中断主流程
report($error);
}
});
第三步:立即返回响应
return $response;
这一步执行完,HTTP连接就已关闭,而日志仍在后台异步落盘——用户感知不到延迟,系统也不会因I/O排队雪崩。
避免协程上下文丢失:在队列任务中安全使用异步IO
很多人把go()直接塞进Laravel的Job::handle()里,结果发现协程根本没跑起来——因为队列worker默认不是协程环境。
① 修改config/queue.php,将swoole驱动设为默认:
'default' => env('QUEUE_CONNECTION', 'swoole'),
② 在app/Jobs/ProcessOrder.php中,不用go(),改用Swoole\Coroutine\run()包裹全部逻辑:
public function handle()
{
Swoole\Coroutine\run(function () {
// 所有协程IO必须放在这里
$db = new Swoole\Coroutine\MySQL();
$db->connect([...]);
$db->query("UPDATE orders SET status='done' WHERE id={$this->id}");
});
}
【切勿在Swoole\Coroutine\run外层调用任何协程IO函数,会直接报错】
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











