通过 Swoole\Table 实现 Swoole 多进程数据共享
第三方存储媒介
前面我们介绍了基于 Swoole 的 Process
及 Process\Pool
模块在 PHP 中实现多进程管理,但是多进程模式下进程间是相互隔离的,无法共享数据和变量,即便是通过 global
定义的全局或超全局变量,也只是在所属进程中有效,如果要在 Swoole 实现的多进程间共享数据,需要借助第三方存储媒介实现:
- 数据库:MySQL、MongoDB
- 缓存:Redis、Memcached
- 磁盘文件
但是这也会引入新的问题,多进程同时操作一条记录或一个文件存在并发访问问题,以数据库操作为例,两个进程可能会同时读取一条数据,或者一个进程对某条记录进行更新处理时,另一个进程也来读取这条记录并进行操作,会导致最终结果数据与预期不一致的情况,这个时候,我们就需要引入锁的概念,当一个进程(比如进程A)对某个记录进行写操作时,对该记录加锁,这样其它进程就无法操作该条记录, 直到进程 A 事务提交再释放这个锁,让其他进程可以进行操作。
内存共享
PHP 相关扩展
对于单机操作来说,除了这些第三方存储媒介之外,还可以通过共享内存的方式实现进程间数据读写操作,有多个 PHP 扩展可以支持共享内存数据操作:
- Semaphore 扩展:可通过该扩展包提供的
shm_get_var
和shm_put_var
函数实现内存共享数据的读写操作; - Shmop 扩展:可通过该扩展包提供的
shmop_read
和shmop_write
函数实现内存共享数据的读写操作; - APCu(APC User Cache)扩展:可通过该扩展包提供的
apc_fetch
和apc_store
实现内存共享数据的读写操作。
Swoole Table
但是上述扩展要么不支持锁,要么高并发时性能比较差,所以 Swoole 自己实现了一个共享内存读写工具 —— Swoole\Table
,该工具是一个基于共享内存和锁实现的高性能并发数据结构,可用于解决多进程/多线程数据共享和同步加锁问题:
- 性能强悍,单线程每秒可读写200万次;
- 应用代码无需加锁,内置行锁自旋锁,所有操作均是多线程/多进程安全,用户层完全不需要考虑数据同步问题;
- 支持多进程,可用于多进程之间共享数据;
- 使用行锁,而不是全局锁,仅当 2 个进程在同一 CPU 时间,并发读取同一条数据才会进行发生抢锁。
Swoole\Table
支持以 Key-Value 方式读写,使用起来非常简单:
- <?php
- // 初始化一个容量为 1024 的 Swoole Table
- $table = new \Swoole\Table(1024);
- // 在 Table 中新增 id 列
- $table->column('id', \Swoole\Table::TYPE_INT);
- // 在 Table 中新增 name 列,长度为 50
- $table->column('name', \Swoole\Table::TYPE_STRING, 10);
- // 在 Table 中新泽 score 列
- $table->column('score', \Swoole\Table::TYPE_FLOAT);
- // 创建这个 Swoole Table
- $table->create();
- // 设置 Key-Value 值
- $table->set('student-1', ['id' => 1, 'name' => '学小君', 'score' => 80]);
- $table->set('student-2', ['id' => 2, 'name' => '学院君', 'score' => 90]);
- // 如果指定 Key 值存在则打印对应 Value 值
- if ($table->exist('student-1')) {
- echo "Student-" . $table->get('student-1', 'id') . ':' . $table->get('student-1', 'name').":".
- $table->get('student-1', 'score') . "\n";
- }
- // 自增操作
- $table->incr('student-2', 'score', 5);
- // 自减操作
- $table->decr('student-2', 'score', 5);
- // 表中总记录数
- $count = $table->count();
- // 删除指定表记录
- $table->del('student-1');
此外 Swoole\Table
类还实现了迭代器接口,支持通过 foreach
进行遍历。
在 Laravel 中使用 Swoole\Table
如果要在 Laravel 中集成 Swoole 使用 Swoole\Table
,以 LaravelS 扩展包为例,首先要在配置文件 config/laravels.php
中定义 swoole_tables
配置项:
- 'swoole_tables' => [
- 'ws' => [ // 表名,会加上 Table 后缀,比如这里是 wsTable
- 'size' => 102400, // 表容量
- 'column' => [ // 表字段,字段名为 value
- ['name' => 'value', 'type' => \Swoole\Table::TYPE_INT, 'size' => 8],
- ],
- ],
- ... // 还可以定义其它表
- ],
然后我们可以在代码中通过swoole
实例上的wsTable
属性访问 SwooleTable:
- class WebSocketService implements WebSocketHandlerInterface
- {
- ...
- // 连接建立时触发
- public function onOpen(Server $server, Request $request)
- {
- // 在触发 WebSocket 连接建立事件之前,Laravel 应用初始化的生命周期已经结束,你可以在这里获取 Laravel 请求和会话数据
- // 调用 push 方法向客户端推送数据,fd 是客户端连接标识字段
- Log::info('WebSocket 连接建立:' . $request->fd);
- app('swoole')->wsTable->set('fd:' . $request->fd, ['value' => $request->fd]);
- $server->push($request->fd, 'Welcome to WebSocket Server built on LaravelS');
- }
- // 收到消息时触发
- public function onMessage(Server $server, Frame $frame)
- {
- foreach (app('swoole')->wsTable as $key => $row) {
- if (strpos($key, 'fd:') === 0 && $server->exist($row['value'])) {
- Log::info('Receive message from client: ' . $row['value']);
- // 调用 push 方法向客户端推送数据
- $server->push($frame->fd, 'This is a message sent from WebSocket Server at ' . date('Y-m-d H:i:s'));
- }
- }
- }
- ...
- }
然后我们参考在 Laravel 中集成 Swoole 实现 WebSocket 服务器这篇教程从客户端向 WebSocket 服务器发起请求,即可在最新日志文件中看到相应的日志信息:
- [2020-04-24 19:39:03] local.INFO: WebSocket 连接建立:1
- [2020-04-24 19:39:07] local.INFO: Receive message from client: 1
通过 Swoole\Table 实现 Swoole 多进程数据共享的更多相关文章
- [b0037] python 归纳 (二二)_多进程数据共享和同步_管道Pipe
# -*- coding: utf-8 -*- """ 多进程数据共享 管道Pipe 逻辑: 2个进程,各自发送数据到管道,对方从管道中取到数据 总结: 1.只适合两个进 ...
- [b0036] python 归纳 (二一)_多进程数据共享和同步_服务进程Manager
# -*- coding: utf-8 -*- """ 多进程数据共享 服务器进程 multiprocessing.Manager 入门使用 逻辑: 20个子线程修改共享 ...
- [b0035] python 归纳 (二十)_多进程数据共享和同步_共享内存Value & Array
1. Code # -*- coding: utf-8 -*- """ 多进程 数据共享 共享变量 Value,Array 逻辑: 2个进程,对同一份数据,一个做加法,一 ...
- swoole table
swoole_table #在内存中建立一张表,用来存放进程交互过程中使用的数据,与memocache似有异曲同工之妙#用法 <?php$table = new swoole_table(204 ...
- Swoole学习(七)Swoole之异步TCP服务器的创建
环境:Centos6.4,PHP环境:PHP7 <?php //创建TCP服务器 /** * $host 是swoole需要监听的ip,如果要监听本地,不对外服务,那么就是127.0.0.1;如 ...
- Swoole学习(三)Swoole之UDP服务器的创建
环境:Centos6.4,PHP环境:PHP7 <?php //创建UCP服务器(UDP服务器相对于TCP服务器通信更可靠些) /** * $host 是swoole需要监听的ip,如果要监听本 ...
- Swoole学习(二)Swoole之TCP服务器的创建
环境:Centos6.4,PHP环境:PHP7 <?php //创建TCP服务器 /** * $host 是swoole需要监听的ip,如果要监听本地,不对外服务,那么就是127.0.0.1;如 ...
- 【swoole】使用swoole简单实现TCP服务
上一篇写到了如何在windows系统上面利用docker快速搭建swoole开发环境,接下来体验下swoole的使用 使用swoole实现tcp服务 <?php $serv = new Swoo ...
- Swoole学习(五)Swoole之简单WebSocket服务器的创建
环境:Centos6.4,PHP环境:PHP7 服务端代码 <?php //创建websocket服务器 $host = '0.0.0.0'; $port = ; $ws = new swool ...
随机推荐
- linux execl()函数 关于execl()函数族的用法不在赘述,
linux execl()函数 关于execl()函数族的用法不在赘述, linux 网络编程 1---(基本概念) 1.TCP和UDP协议 共同点:同为传输层协议 不同点: TCP:有连接,可靠 U ...
- Android适配器
Android适配器 安卓的适配器在我看来是一个非常重要的知识点,面对形式相同但数据源较多的情况时,适配器是一个比较好的解决方法.数据适配器是建立了数据源与控件之间的适配关系,将数据源转换为控件能够显 ...
- 【SQL SERVER】索引
在做开发过程中经常会接触数据库索引,不只是DBA才需要知道索引知识,了解索引可以让我们写出更高质量代码. 索引概述 聚集索引 非聚集索引 唯一索引 筛选索引 非聚集索引包含列 索引概述 索引的存在主要 ...
- NLP(二十八)多标签文本分类
本文将会讲述如何实现多标签文本分类. 什么是多标签分类? 在分类问题中,我们已经接触过二分类和多分类问题了.所谓二(多)分类问题,指的是y值一共有两(多)个类别,每个样本的y值只能属于其中的一 ...
- 写给程序员的机器学习入门 (二) - pytorch 与矩阵计算入门
pytorch 简介 pytorch 是目前世界上最流行的两个机器学习框架的其中之一,与 tensoflow 并峙双雄.它提供了很多方便的功能,例如根据损失自动微分计算应该怎样调整参数,提供了一系列的 ...
- Pointer Lock API(3/3):一个Demo
简单的Demo演练 点击跳转至Code Pen以查看演示和源码 完整代码 <!DOCTYPE HTML> <html lang="en-US"> <h ...
- JavaScript-原始值和引用值
一.原始值和引用值的概念 在 ECMAScript 中,变量可以存在两种类型的值,即原始值和引用值. 1.1 原始值 (1)原始值指的是 原始类型 的值,也叫 基本类型,例如 Number.Stirn ...
- ClickHouse学习系列之三【配置文件说明】
背景 最近花了些时间看了下ClickHouse文档,发现它在OLAP方面表现很优异,而且相对也比较轻量和简单,所以准备入门了解下该数据库系统.在介绍了安装和用户权限管理之后,本文对其配置文件做下相关的 ...
- Redis 笔记(六)—— ZSET 常用命令
常用命令 命令 用例和描述 ZADD ZADD key-name score member [score member ...] —— 将带有分值的成员添加到 HSET 中 ZREM ZREM key ...
- composer换源,composer切换国内源
首先要分清楚是局部换源还是全局换源 1.局部换源(仅对当前项目有效) 在当前项目下的composer.json中添加 { "repositories": [ { "typ ...