php 8.1+ 用 swoole 导入数据的核心是确保协程环境就绪、使用协程化 io 组件(如 swoole\coroutine\mysql)、复用连接与客户端、合理分批提交事务,并正确配置 swoole_table 结构。

PHP 8.1+ 用 Swoole 导入数据,核心不是“怎么导入”,而是“别用同步方式硬扛”——否则并发一上来就卡死、超时、连接池耗尽。
协程环境没启动,go() 和 co::sleep() 直接报错
常见错误现象:Fatal error: Uncaught Error: Call to undefined function go() 或 must be called in the coroutine。这不是代码写错了,是根本没进协程上下文。
- CLI 场景:必须用
Swoole\Coroutine\run()包一层,不能直接跑脚本 - Web 场景:不能在 Laravel/ThinkPHP 的 FPM 请求里调
go(),得走think-swoole或自建Swoole\Http\Server - 验证方法:运行
php -r "var_dump(extension_loaded('swoole') && function_exists('go'));",两个都为true才算基础就绪
批量导入 MySQL,别碰 PDO/mysqli
用传统扩展导入 10 万条数据?哪怕开了事务,也是一条一条阻塞执行,协程调度器被锁死,其他请求全等。
- 必须换
Swoole\Coroutine\Mysql客户端,它底层用异步 IO + 协程挂起,不占 worker 线程 - 连接池要手动管理:单次
connect()后复用,别每个协程都新建连接(会快速打满max_connections) - 大事务慎用:
START TRANSACTION+ 10 万行INSERT+COMMIT仍可能锁表或 OOM;建议每 1000 行COMMIT一次 - 示例关键片段:
$db = new Swoole\Coroutine\Mysql(); $db->connect(['host' => '127.0.0.1', 'user' => 'root', 'password' => '', 'database' => 'test']); go(function () use ($db, $rows) { $db->query('TRUNCATE TABLE import_log'); foreach (array_chunk($rows, 1000) as $chunk) { $db->query("INSERT INTO import_log (...) VALUES " . implode(',', array_map(fn($r) => "(...)", $chunk))); } });
文件读取和网络请求还在用 file_get_contents / curl_exec?立刻停手
这两个函数在协程里是“黑洞”,调一次,整个 worker 就停 3 秒——不是协程挂起,是线程真卡住。
- 读本地 CSV/JSON:改用
Swoole\Coroutine\FileSystem::readFile(),它返回string而非资源,且不阻塞 - 从远程 API 拉数据:必须用
Swoole\Coroutine\Http\Client,支持set(['timeout' => 5])和get()/post() - 注意 DNS 解析:默认走系统同步解析,会拖慢首次请求;加
'enable_coroutine_dns' => true到 Server 配置里启用协程 DNS - 别在循环里反复 new Client:复用一个 client 实例,只改
setDefer()和路径即可发多个请求
swoole_table 写入后 get 不到?键名和结构早锁死了
想用 swoole_table 做导入中间状态(比如记录某批次已处理行数),结果 get('progress') 总是 false?大概率栽在这三点上。
- 键名严格区分大小写:
$table->set('Progress', 123)和$table->get('progress')完全不匹配 - 字段定义后不可改:初始化时
$table->column('status', Swoole\Table::TYPE_STRING, 32),之后存'processing'(11 字符)没问题,但存'done_with_long_reason'(22 字符)就会截断甚至写失败 - 字符串长度含
\0:column('name', TYPE_STRING, 6)最多存 5 字符 + 1 个终止符,"admin" 刚好,"administrator" 就溢出 - 安全写法:
$table = new Swoole\Table(1024); $table->column('batch_id', Swoole\Table::TYPE_INT, 8); $table->column('processed', Swoole\Table::TYPE_INT, 4); $table->create(); $table->set('import_20260509', ['batch_id' => 123, 'processed' => 0]); // 键名用下划线,全小写
真正卡住导入性能的,往往不是 SQL 本身,而是协程上下文没切对、IO 调用没协程化、共享内存结构没对齐——这些地方一错,开再多 worker 也白搭。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











