Workerman 常驻内存编程

定位

Workerman 是纯 PHP 的常驻内存网络库,不是框架。它提供事件循环、TCP/UDP/WebSocket 服务端、定时器、进程管理。

它的定位是「让 PHP 能做长连接和常驻进程」,而不是「替代 Laravel」。

安装

composer require workerman/workerman

要求 PHP >= 8.1 的 CLI 环境,不需要额外扩展(不像 Swoole 需要编译安装)。

版本现状:当前稳定版是 5.1.0(2025-02 发布)。5.0(2025-01)补上了 Fiber / Swoole / Swow 三种协程后端的适配,5.1 则提供了统一的 Workerman\Coroutine 类,并配齐 Context、Channel、Barrier、Parallel、WaitGroup 等协程组件。注意协程不是自动启用的:用哪种实现要显式指定事件循环驱动(例如装好 revolt/event-loop 后 Worker::$eventLoopClass = \Workerman\Events\Fiber::class;,或选 Swoole / Swow 的驱动类),指定之后协程 API 才按该后端工作。安装时建议直接锁定 workerman/workerman:~5.1。

最小示例

一个 HTTP 服务

<?php
// http_server.php
require_once __DIR__ . '/vendor/autoload.php';

use Workerman\Worker;

$http = new Worker('http://0.0.0.0:8080');

$http->onMessage = function ($connection, $request) {
    $connection->send("Hello, {$request->get('name', 'world')}");
};

Worker::runAll();
php http_server.php start      # 前台运行
php http_server.php start -d   # 后台守护
php http_server.php stop
php http_server.php status

一个 WebSocket 服务

<?php
use Workerman\Worker;

$ws = new Worker('websocket://0.0.0.0:8282');
$ws->count = 4;                        // 开 4 个进程

// 保存所有连接
$connections = [];

$ws->onConnect = function ($conn) use (&$connections) {
    $connections[$conn->id] = $conn;
};

$ws->onMessage = function ($conn, $data) use (&$connections) {
    // 广播给所有人
    foreach ($connections as $c) {
        $c->send("someone said: {$data}");
    }
};

$ws->onClose = function ($conn) use (&$connections) {
    unset($connections[$conn->id]);
};

Worker::runAll();

核心概念

1. 事件循环 + 回调

Workerman 的核心是 EventLoop(底层用 epoll / select)。你注册回调,它负责在事件发生时调用:

$worker->onConnect    = fn($conn) => ...;   // 连接建立
$worker->onMessage    = fn($conn, $data) => ...;  // 收到数据
$worker->onClose      = fn($conn) => ...;   // 连接关闭
$worker->onError      = fn($conn, $code, $msg) => ...;

2. 多进程模型

$worker->count = 4 会 fork 出 4 个子进程,每个进程独立处理连接。进程之间不共享内存,要通信得用 Redis、共享内存或 Workerman 自带的 channel 组件。

这是和 Swoole 的主要差异之一:Swoole 的协程是 C 扩展原生实现,吞吐与调度效率更高;Workerman 5.x 虽然也能用协程,但那是 PHP 层抽象——装了 Swoole / Swow 就借用它们的原生协程,否则退化为 Fiber 模拟。默认路径仍是多进程 + 事件循环,协程是可选能力而非默认模型。

3. 定时器

use Workerman\Timer;

// 每 2 秒执行一次
Timer::add(2, function () {
    echo "tick\n";
});

// 只执行一次
Timer::add(5, fn() => echo "once\n", [], false);

常驻进程里的定时任务比 crontab 更精确、开销更低。这是 Workerman 一个被低估的用途。

常见坑

① 进程数不是越多越好

count 设成 CPU 核数的 1-4 倍即可。设太大会增加进程切换开销。而且每个进程独立占内存,PHP 的常驻内存不小。

② 全局变量不跨进程

$count = 0;
$worker->count = 4;
$worker->onMessage = function ($conn) use (&$count) {
    $count++;    // 每个进程各算各的,总数对不上
};

要统计全局数据,用 Redis 的 INCR。

③ 内存只增不减

常驻进程跑久了内存上涨,通常是:连接对象没清理、数组只 add 不 unset、闭包捕获了大对象。要么定期重启(对本文的示例就是 php http_server.php restart,配合定时任务),要么严格管理内存。

④ 不能直接跑 Laravel/ThinkPHP

Workerman 是库不是框架。要用框架的路由、ORM,得自己桥接(或者用现成的 Webman)。

什么时候选它

  • 需要 WebSocket、TCP 长连接、MQTT、物联网接入
  • 需要自定义协议(二进制协议、心跳、私有协议)
  • 需要高频定时任务
  • 想给现有项目加一个常驻进程,不想引入整个框架

不选它的场景:普通 HTTP API(用 FPM 或框架)、需要框架生态(用 Webman)、需要高并发下更激进的协程吞吐(用 Swoole / Hyperf)。

一个实际用途:替代 crontab

很多场景下 Workerman 的定时器比系统 crontab 更合适:

$worker = new Worker();
$worker->count = 1;

// 每秒检查一次队列,比 crontab 的分钟级精度高
Timer::add(1, function () {
    // 消费队列
});

Worker::runAll();

优势:精度高(毫秒级)、不用起进程(复用常驻进程)、能看到实时日志。 代价:进程挂了任务就停,需要配合进程守护(start -d 自带守护,或交给 systemd)。

延伸阅读

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇