代码改变世界

Swoole 中使用 Table 内存表实现进程间共享数据

2020-07-19 11:10  小伍2013  阅读(820)  评论(0编辑  收藏  举报

背景

在多进程模式下进程之间的内存是相互隔离的,在一个工作进程中的全局变量和超全局变量,在另一个工作进程中是无法读取和操作的。

如果只有一个工作进程,则不存在进程隔离问题,可以使用全局变量和超全局变量。

要实现进程间共享数据,我们可以使用第三方的 Redis 内存数据库或 Swoole 内置的 Table 共享内存来实现。

Table 的优势

  • 性能强悍,单线程每秒可读写 200 万次;
  • 应用代码无需加锁,Table 内置行锁自旋锁,所有操作均是多线程 / 多进程安全。用户层完全不需要考虑数据同步问题;
  • 支持多进程,Table 可以用于多进程之间共享数据;
  • 使用行锁,而不是全局锁,仅当 2 个进程在同一 CPU 时间,并发读取同一条数据才会进行发生抢锁。

使用示例:

<?php
// 实例化一个占用的共享内存大小为1024的内存表
$table = new Swoole\Table(1024);
// 内存表增加3列
$table->column('fd', Swoole\Table::TYPE_INT);
$table->column('reactor_id', Swoole\Table::TYPE_INT);
$table->column('data', Swoole\Table::TYPE_STRING, 64);
$table->create();

$serv = new Swoole\Server('127.0.0.1', 9501);
// 设置数据包分发策略:轮循模式
$serv->set(['dispatch_mode' => 1]);
$serv->table = $table;

$serv->on('receive', function ($serv, $fd, $reactor_id, $data) {
    $cmd = explode(" ", trim($data));

    if ($cmd[0] == 'get') {
        //get self
        if (count($cmd) < 2) {
            $cmd[1] = $fd;
        }
        $get_fd = intval($cmd[1]);
        $info = $serv->table->get($get_fd);
        $serv->send($fd, var_export($info, true) . "\n");
    } elseif ($cmd[0] == 'set') {
        // 使用连接的文件描述符作为key写入内存表
        $ret = $serv->table->set($fd, array('fd' => $fd, 'reactor_id' => $reactor_id, 'data' => $cmd[1]));
        if ($ret === false) {
            $serv->send($fd, "ERROR\n");
        } else {
            $serv->send($fd, "OK\n");
        }
    } else {
        $serv->send($fd, "command error.\n");
    }
});

$serv->start();