Workerman协程多进程下无法共享PHP变量,因各进程内存隔离;可用Redis实现原子读写、信号通知轻量同步、消息队列解耦共享逻辑。

Workerman协程多进程环境下无法直接共享PHP变量,因为每个Worker进程拥有独立内存空间,协程又运行在各自进程内,【任何跨进程的变量赋值、引用或全局static变量操作都无效】,强行使用会导致数据错乱或静默丢失。
为什么不能用常规变量共享
Workerman默认启动多个子进程(如设置count=4),每个进程加载一次代码、初始化一次全局变量;协程在单个进程内调度,但不会跨越进程边界。即使启用了Swoole/Swow/Fiber协程驱动,也只在当前进程内生效,【协程不是进程间通信机制】。
例如,在一个Worker进程中对$counter++,其他3个Worker进程里的$counter仍是初始值,彼此完全隔离。
用Redis实现安全读写计数器
这是最常用且生产就绪的方案:所有进程统一读写Redis,利用其原子命令保障并发安全。
第一步:安装并启用redis扩展(php -m | grep redis需有输出)
第二步:在Worker启动前初始化Redis连接(推荐使用predis或phpredis)
第三步:用INCR/DECR/GET等原子命令操作共享状态
示例代码(使用phpredis):
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 安全递增
$redis->incr('shared_counter');
// 安全读取
$value = $redis->get('shared_counter');
用Workerman内置Timer+进程间信号做轻量同步
适用于仅需通知、不涉及复杂状态传递的场景,比如触发某进程执行一次清理任务。
方法一:用Worker::$pidMap广播信号
foreach (Worker::$pidMap as $pid) {
posix_kill($pid, SIGUSR1);
}
方法二:在Worker中监听信号并注册回调
pcntl_signal(SIGUSR1, function () {
echo "收到刷新指令\n";
// 执行本地缓存重载等操作
});
pcntl_signal_dispatch();
注意:信号无法携带数据,仅适合广播简单指令,不能传值或返回结果。
用消息队列解耦共享逻辑
当共享行为涉及业务规则、需顺序执行或带上下文时,用AMQP(RabbitMQ)或Redis Stream替代直接读写。
步骤一:各Worker进程向同一队列推送“更新请求”消息
步骤二:单独起一个消费者Worker订阅该队列
步骤三:消费者串行处理每条消息,更新Redis或数据库
这样避免了多进程同时修改同一资源的竞争,也规避了锁粒度粗、阻塞协程的问题。

















