mysqli::reap_async_query() 用于收割已执行的异步查询结果,必须配合 mysqli::real_query() 和 mysqli_async 才生效;若未调用,后续查询将因连接阻塞而失败。

mysqli 在 PHP 8.4 中本身不支持异步查询——它仍是同步阻塞式 API。真正提供异步能力的是底层驱动 mysqlnd,且必须配合特定调用模式(非 mysqli::query() 直接调用),否则根本不会进入异步流程。
你看到的 MYSQLI_ASYNC 标志、mysqli_poll()、reap_async_query() 等,全部依赖 mysqlnd 驱动 + 手动连接管理 + 多连接并发,不是“给 query 加个 flag 就变异步”。
mysqli::query() 传 MYSQLI_ASYNC 没用
这是最常见的误解。以下代码看似启用异步,实则完全无效:
$mysqli->query("SELECT 1", MYSQLI_ASYNC); // ❌ 不会异步,MYSQLI_ASYNC 在 query() 中被忽略
mysqli::query() 的第二个参数 result_mode 只接受 MYSQLI_STORE_RESULT、MYSQLI_USE_RESULT 或 MYSQLI_ASYNC —— 但 MYSQLI_ASYNC 在该方法中**无实现逻辑**,会被静默丢弃。官方文档也明确标注:此常量仅用于 mysqlnd 内部,不作用于 query()。
- 真正触发异步行为的是
mysqli::real_query()(或过程式mysqli_real_query()) -
MYSQLI_ASYNC必须和real_query()搭配使用,且后续必须手动轮询+收割 - 直接调用
query()即使传了MYSQLI_ASYNC,仍走同步路径,连接被阻塞
正确启用 mysqlnd 异步的三步硬要求
缺一不可,否则连接卡死、mysqli_poll() 返回 0、或抛出 Commands out of sync 错误。
-
驱动必须是 mysqlnd:运行
php -i | grep mysqlnd,确认输出含mysqlnd;若显示libmysqlclient(尤其在旧 CentOS 或编译安装时),异步功能完全不可用 -
每个异步查询必须独占一个 mysqli 连接:不能复用同一
$mysqli实例发多个real_query(..., MYSQLI_ASYNC)—— mysqlnd 不支持单连接多异步请求 -
必须用 mysqli_poll() 等待就绪,再用 reap_async_query() 获取结果:跳过
mysqli_poll()直接调reap_async_query()会返回false;不调reap_async_query()就执行下一个real_query(),触发Commands out of sync
实际能跑通的最小异步示例(PHP 8.4)
注意:这不是“一行开启异步”,而是显式管理连接、轮询、收割的完整闭环。
$links = [];
foreach ([1, 2, 3] as $i) {
$link = new mysqli('localhost', 'user', 'pass', 'db');
$link->real_query("SELECT SLEEP(2) AS n", MYSQLI_ASYNC); // ✅ 正确入口
$links[] = $link;
}
<p>$read = $errors = $reject = $links;
while (count($links)) {
$n = mysqli_poll($read, $errors, $reject, 5); // 最多等 5 秒
if ($n > 0) {
foreach ($read as $link) {
$result = $link->reap_async_query(); // ✅ 必须调用
if ($result) {
var_dump($result->fetch_row());
$result->free();
$link->close();
$links = array_filter($links, fn($l) => $l !== $link);
}
}
$read = $errors = $reject = array_values($links); // 重置数组索引
}
}</p>
关键点:
-
real_query()启动异步,reap_async_query()收割结果,二者成对出现 -
mysqli_poll()是唯一安全等待方式;用usleep()轮询会浪费 CPU 且不准 - 每个
$link只能发一次异步查询,用完即关,不可复用
比原生异步更现实的选择:协程或连接池
纯 mysqlnd 异步在 PHP 8.4 中维护成本高、易出错、无法复用连接,实际项目中极少直接使用。更可行的路径是:
- 用
Swoole或OpenSwoole的Coroutine\MySQL:API 兼容 mysqli,自动处理异步/协程调度,连接可复用 - 用
ext-async(如 amphp/mysql):基于 event loop,无需手动poll/reap - 用 PDO + 连接池(如 laravel/octane + roadrunner):靠多 worker 并行,而非单进程内异步
原生 mysqli 异步只适合极少数场景:比如 CLI 工具需并发拉取多个慢查询,且不能引入扩展。Web 请求中强行套用,反而因连接爆炸、内存泄漏、超时混乱而降低吞吐。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











