Workerman协程需替换阻塞调用:Swoole/Swow自动协程化file_get_contents/curl_exec,Fiber/Revolt必须手动替换;HTTP改用workerman/http-client或Swow\Http\Client,MySQL换workerman/mysql,文件IO按驱动选择协程API。

Workerman协程新手常遇到的问题是:写好的同步HTTP请求、数据库查询或文件读取代码,在协程环境下直接运行会卡死整个worker进程,导致并发能力归零。这不是代码逻辑错了,而是PHP原生阻塞函数在协程中未被自动接管——必须显式替换为协程兼容的调用方式。
确认当前协程驱动类型
第一步不是改代码,而是看清楚你正在用哪种协程引擎。打开启动脚本(如start.php),检查Worker实例是否设置了eventLoop属性:
若看到$worker->eventLoop = \Workerman\Events\Swoole::class;,说明你在用Swoole驱动;若为\Workerman\Events\Swow::class,则是Swow;若为\Workerman\Events\Revolt::class或\Workerman\Events\Fiber::class,则走的是Fiber/Revolt路线。
【关键前提】只有Swoole和Swow能自动协程化file_get_contents、curl_exec等函数;Fiber/Revolt做不到这点,必须手动替换所有阻塞调用,否则协程会假死。
HTTP请求改造:从curl_exec到协程客户端
方法一:使用Workerman官方协程HTTP客户端(推荐)
1. 执行composer require workerman/http-client安装组件。
2. 在onMessage回调里创建Client实例:$client = new Workerman\Http\Client();
3. 用await发起GET请求:$response = await $client->get('https://api.example.com/user?id=123');
4. 获取响应体:$body = await $response->getBody();——这一步不能用json_decode($body)直接解析,要先确保$body是字符串,否则会报错。
方法二:Swow用户直接用Swow\Http\Client
若已启用Swow驱动,可跳过workerman/http-client,改用原生Swow客户端:$response = (new Swow\Http\Client())->get('https://api.example.com/data');。注意它返回的是Promise对象,仍需await才能取值,不await就直接用会得到空结果。
MySQL查询改造:从PDO到workerman/mysql
第一步:卸载旧的PDO连接逻辑,包括new PDO()、$pdo->query()、$stmt->fetch()整套流程。
第二步:执行composer require workerman/mysql安装协程MySQL驱动。
第三步:在Worker初始化阶段建立连接池式连接:$db = new Workerman\Mysql\Connection('127.0.0.1', 3306, 'user', 'pass', 'dbname');
第四步:在业务逻辑中改写查询语句——原来$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?"); $stmt->execute([$id]); $row = $stmt->fetch();,现在变成:$row = await $db->select('*')->from('users')->where(['id' => $id])->query();
注意:workerman/mysql不支持预处理占位符以外的任意SQL拼接,【禁止】把用户输入直接拼进SQL字符串,否则会触发语法错误且无法利用连接池。
文件与IO操作改造:避免file_get_contents假死
① 若你用的是Swoole或Swow驱动:可以保留file_get_contents,它们会自动将其协程化,但仅限本地文件路径(如/tmp/config.json)。网络URL仍需用协程HTTP客户端。
② 若你用的是Fiber/Revolt驱动:file_get_contents会彻底阻塞,必须换成Workerman\IO\FileSystem或Swow\IO\Stdio(Swow场景)。
例如读取配置文件:$content = await Workerman\IO\FileSystem::readFile('/path/to/config.json');
写入日志不能用file_put_contents,否则高并发下IO瓶颈明显——应投递到异步写入队列,或改用Workerman\Logger内置的异步刷盘机制。

















