avatar

mdo

Hello

  • 首页
  • 知识库
  • 归档
  • 标签
  • 关于
主页 利用 Swoole 协程特性
文章

利用 Swoole 协程特性

发表于 2026-06-26 更新于 2026-06- 26
作者 mdo
7~9 分钟 阅读

默认配置 task_worker_num => 4 在面对批量推送消息时严重不足。当需要给成百上千个用户推送消息时,循环调用 Swoole 的 push 或投递大量小任务,会瞬间挤爆这 4 个进程,导致后续任务全部排队甚至超时。

请按照以下分级方案进行优化,方案一和方案二可以立即见效:

方案一:立即调整配置(治标)

在批量推送场景下,进程主要在等待网络 I/O 响应,属于 I/O 密集型 任务。你可以大胆地将进程数放大。

修改 config/swoole.php 中的 options:

php

'options' => [
    // 1. 大幅提升进程数:建议调整为 16 或 32(甚至 64,取决于你的用户量和服务器内存)
    'task_worker_num' => 32, 

    // 2. 必须调大任务队列缓冲区(防止任务因为堆积而直接丢弃或报错)
    'task_max_request' => 2000,
    'socket_buffer_size' => 128 * 1024 * 1024, // 128M
],

请谨慎使用此类代码。

方案二:改变投递策略(治本)

绝对不要在循环中为每个用户单独投递一个 Task(例如:循环 1000 次投递 1000 个 Task)。这会产生高额的进程间通信(IPC)开销。

正确做法:打包成一个或数个大任务投递。

  • 错误写法:

    php

    // 导致 task 瞬间不够用的元凶
    foreach ($userIds as $id) {
        $server->task(['type' => 'push', 'uid' => $id, 'msg' => $data]);
    }
    

    请谨慎使用此类代码。

  • 正确写法(分批打包):

    php

    // 将 10000 个用户切分成每 500 个一组,只投递 20 个 Task
    $chunks = array_chunk($userIds, 500); 
    foreach ($chunks as $chunkUids) {
        $server->task(['type' => 'batch_push', 'uids' => $chunkUids, 'msg' => $data]);
    }
    

    请谨慎使用此类代码。

  • 在 Task 消费端处理:

    php

    // 在 onTask 事件中拿到一组 uids 循环 push
    foreach ($data['uids'] as $uid) {
        if ($server->isEstablished($fd)) { // 确保连接有效
            $server->push($fd, $data['msg']);
        }
    }
    

    请谨慎使用此类代码。

方案三:利用 Swoole 协程特性(高性能选型)

推送消息本身是非常适合协程的。如果开启了协程,你甚至可以不用 Task 进程,直接在 Worker 中利用协程并发去推送,速度会比 Task 快数倍。

  1. 确保 config/swoole.php 开启了 'coroutine' => true。

  2. 使用 Swoole\Coroutine\Barrier 或通道(Channel)并发推送:

php

use Swoole\Coroutine;
use Swoole\Coroutine\Barrier;

// 在 WebSocket 路由或事件中直接执行
Coroutine::create(function() use ($userIds, $data, $server) {
    $barrier = Barrier::create();
    $chunks = array_chunk($userIds, 100); // 100个一组并发

    foreach ($chunks as $chunk) {
        // 自动并发,利用底层协程调度,不阻塞当前进程
        Coroutine::create(function() use ($barrier, $chunk, $data, $server) {
            foreach ($chunk as $uid) {
                $fd = getFdByUid($uid); // 自定义获取 fd 的方法
                if ($server->isEstablished($fd)) {
                    $server->push($fd, $data);
                }
            }
        });
    }
    // 等待这一批全部送达
    Barrier::wait($barrier);
});

技术
许可协议:  CC BY 4.0
分享

相关文章

10月 2, 2026

iOS 侧载(Sideloading)工具

AltStore 和 Sideloadly 都是目前最流行的 iOS 侧载(Sideloading)工具。 简单来说,它们的作用就是让你绕过苹果的官方 App Store,直接把第三方的 IPA 安装包(也就是 iOS 的应用安装文件)安装到你的 iPhone 或 iPad 上。 通过这两个工具,你

9月 28, 2026

注册 Chat Participant

将当前服务接入 VS Code 的 AI 聊天窗口是完全可行的。VS Code 在近期的版本中正式推出了 Chat Extensions API(github.copilot.chat),允许第三方扩展将自定义的 LLM 服务或工具注册到 Copilot Chat 面板中。 结合当前 code_ge

9月 23, 2026

php intelephense 设置 if 空格

在 VS Code 中,如果你使用的是 PHP Intelephense 插件,控制 if 关键字后面是否加空格的设置是由其内置的格式化引擎(基于 PSR-12 标准)决定的。 你可以通过修改 VS Code 的 settings.json 来配置这个行为: 1. 开启 if 后面的空格(默认/推荐

下一篇

Linux | Reqable · API抓包调试 + API测试一站式工具

上一篇

think-swoole 全局广播

最近更新

  • 比尔盖茨的智慧:想多赚钱,就每天循环做这3件事
  • iOS 侧载(Sideloading)工具
  • 程序员越想创业,越不要急着动手
  • 注册 Chat Participant
  • 中秋给在外游子的一封信

热门标签

API CodeGeex Coding Cursor DeepSeek Docker Gitkraken Harness Laravel Management

目录

©2026 mdo. 保留部分权利。