解释一下 Workerman 中使用 global 问题

283 天前
cs5117155  cs5117155
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';

// 创建一个 Worker 监听 2345 端口,使用 http 协议通讯
$http_worker = new Worker("http://0.0.0.0:2345");

// 启动 1 个进程对外提供服务
$http_worker->count = 1;
$http_worker->onWorkerStart = function ($worker) {
// 将 db 实例存储在全局变量中(也可以存储在某类的静态成员中)
    global $a;
    $a=0;
};
// 接收到浏览器发送的数据时回复 hello world 给浏览器
$http_worker->onMessage = function(TcpConnection $connection, Request $request)
{
    global $a;
    $a++;
    // 向浏览器发送 hello world
    $connection->send("hello world---$a");
};

// 运行 worker
Worker::runAll();

为何浏览器每次运行不是递增,而是 1,3,5,7,9....这样的

能否从计算机原理基础解释一下吗,我看 workman 文档说进程间的共享数据,可以用全局变量,或者管道,或者 redis 这样的存储工具,我声明了一个 global,该进程也是只有 1 个,读取$a 的时候,只会从$a 地址读取值,但是值每次都不是递增,实在想不通

1580 次点击
所在节点   PHP  PHP
15 条回复
b821025551b
b821025551b
283 天前
$a++ 后面打 log 进文件,看具体怎么执行的。
sun2920989
sun2920989
283 天前
看看浏览器是不是自动多请求了一次图标文件.
sun2920989
sun2920989
283 天前
或者换命令行或 postman 之类的工具再试试.
cs5117155
cs5117155
283 天前
@sun2920989 如果开了一个进程,确实多请求图标导致。但是如果我开了 4 个进程
hello world---4 ➜ ✗ curl http://127.0.0.1:2345
hello world---1 ➜ ✗ curl http://127.0.0.1:2345
hello world---1 ➜ ✗ curl http://127.0.0.1:2345
hello world---1 ➜ ✗ curl http://127.0.0.1:2345
hello world---1 ➜ ✗ curl http://127.0.0.1:2345
hello world---2 ➜ ✗ curl http://127.0.0.1:2345
hello world---2 ➜ ✗ curl http://127.0.0.1:2345
hello world---2 ➜ ✗ curl http://127.0.0.1:2345
hello world---3 ➜ ✗ curl http://127.0.0.1:2345
hello world---3 ➜ ✗ curl http://127.0.0.1:2345
hello world---2 ➜ ✗ curl http://127.0.0.1:2345
hello world---4 ➜ ✗ curl http://127.0.0.1:2345
hello world---5 ➜ ✗ curl http://127.0.0.1:2345
为何它$a 请求不一样,是因为我请求的时候是无状态,每次请求会从 4 个进程中随机选取一个,然后再进行$a++,所以每次请求的$a ,不一定是上一次请求的进程?
sundev
sundev
283 天前
一看就是浏览器多请求的。
还有如果多进程,workerman 是没有会话级别负载均衡的,就是从空闲的进程分配一个来处理的。
sundev
sundev
283 天前
你如果的确需要真全局变量的,你可以使用 https://github.com/walkor/GlobalData 来实现,或者用个缓存组件来做。
javalaw2010
javalaw2010
283 天前
@cs5117155 workerman 是多进程的,你用 global 声明,其实只在当前的进程内有效,Worker::runAll()之后,进程就 fork 了,此时你的 global 变量在每个进程里都是独立的。
cs5117155
cs5117155
283 天前
@javalaw2010 谢谢,这样说,我就明了很多了,有时看文档说,进程间数据不互通,都是独立,需要编程者自已实现互通,总感觉就停留在似懂非懂的状态
sun2920989
sun2920989
283 天前
@cs5117155 进程间的 global 不是互通的.
cs5117155
283 天前
@sun2920989 那我还想问一个问题,我在 workman 里面使用 Mysql 获取数据,workman 开启 4 个进程,每一个 tcp 请求进来,通过数据库查询 A 用户金额,那么 4 个进程中获取 A 用户金额肯定是不变的吧,数据的变动只依赖数据库有无改动
sun2920989
283 天前
@cs5117155 如果您数据库的值没有变 那么四个进程去查询的结果当然是一样的. 另外请注意四个进程每个要使用一个独立的数据库连接.不要共享数据库连接.
cs5117155
283 天前
@sun2920989 在 workman 文档 https://www.workerman.net/doc/workerman/components/workerman-mysql.html 。看到在 onWorkerStart 回调中初始化数据库连接,并设置 global $db ,$worker->onMessage 使用$db 的连接查询,Worker::runAll()之后,进程就开始 4 个 fork 了,有 4 个进程,那么这时 global $db 都是 4 个相互独立的数据库连接吧,并没有发生共享数据库连接的情况?
ivanshaoaz
283 天前
@cs5117155 #12 我的理解:onWorkerStart 回调函数会在每个 worker 进程启动时执行,这个回调中初始化的任何变量都是这个进程独有的,初始化的 $db 变量对于每个 worker 进程是独立的,不会发生共享。
cs5117155
283 天前
@ivanshaoaz 感谢。我也是这样认为
sun2920989
283 天前
@cs5117155 是的 您和 13 楼说的完全正确.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1043161

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX