开启task_enable_coroutine后,onTask中可直接使用协程API;需配合enable_coroutine=true,参数变为SwooleServerTask对象,必须调用$task->finish(),且仅支持Swoole≥4.4.0。
不开启时,onTask 回调运行在普通同步上下文中,调用 SwooleCoroutineMySQL 或 co::sleep() 会直接报错:Fatal error: Uncaught SwooleError: Must be called in the coroutine context。开启后,Swoole 在每次执行 onTask 前自动创建一个协程,你写的代码就像在 go() 里一样自然。
关键点:
task_enable_coroutine 必须和 enable_coroutine => true 同时生效(后者是全局协程开关,默认已开启)onTask 的第二个参数类型变为 SwooleServerTask 对象,而不是旧版的 $taskId、$srcWorkerId 等离散参数$server->finish(),必须调用 $task->finish() 返回结果,否则数据收不到如果你关了 task_enable_coroutine(设为 false),又想在 onTask 中发 HTTP 请求或查数据库,唯一办法是手动启动协程:
<pre class="brush:php;toolbar:false;">$server->on('Task', function ($server, $taskId, $srcWorkerId, $data) { go(function () use ($data) { $client = new SwooleCoroutineHttpClient('api.example.com', 80); $client->get('/status'); $server->finish($client->getBody()); });});
这种写法不仅冗余,还容易漏掉错误处理、超时控制,更麻烦的是:协程内无法访问 $server 实例(因为 <code>$server 不是协程安全对象),$server->finish() 调用会失败 —— 你得把 $server 传进去或改用全局引用,极易出错。
task_async 是 Swoole 早期为 Task 进程引入异步能力的尝试,但它存在严重设计缺陷:
Server::finish() 可能写到错误的任务 IDenable_coroutine 后 task_async 会被忽略甚至引发崩溃所以现在只有一条路:用 task_enable_coroutine => true + SwooleServerTask 对象 + $task->finish(),其他组合都是过时或危险的。
最常踩的不是功能不会用,而是环境没对齐:
task_enable_coroutine 仅在 Swoole ≥ 4.4.0 有效;低于此版本设了也无效,且不会警告opcache.enable_cli=1,某些协程客户端(如 SwooleCoroutineRedis)可能因类加载顺序异常而报 Class not found
onShutdown 回调里不能用协程 API —— 此时协程调度器已退出,哪怕开了 task_enable_coroutine 也没用真正要验证是否生效,别只看配置有没有设,直接在 onTask 里写一行 co::sleep(0.01),不报错就说明环境通了。