第三方存储媒介

前面我们介绍了基于 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 多进程数据共享的更多相关文章

  1. [b0037] python 归纳 (二二)_多进程数据共享和同步_管道Pipe

    # -*- coding: utf-8 -*- """ 多进程数据共享 管道Pipe 逻辑: 2个进程,各自发送数据到管道,对方从管道中取到数据 总结: 1.只适合两个进 ...

  2. [b0036] python 归纳 (二一)_多进程数据共享和同步_服务进程Manager

    # -*- coding: utf-8 -*- """ 多进程数据共享 服务器进程 multiprocessing.Manager 入门使用 逻辑: 20个子线程修改共享 ...

  3. [b0035] python 归纳 (二十)_多进程数据共享和同步_共享内存Value & Array

    1. Code # -*- coding: utf-8 -*- """ 多进程 数据共享 共享变量 Value,Array 逻辑: 2个进程,对同一份数据,一个做加法,一 ...

  4. swoole table

    swoole_table #在内存中建立一张表,用来存放进程交互过程中使用的数据,与memocache似有异曲同工之妙#用法 <?php$table = new swoole_table(204 ...

  5. Swoole学习(七)Swoole之异步TCP服务器的创建

    环境:Centos6.4,PHP环境:PHP7 <?php //创建TCP服务器 /** * $host 是swoole需要监听的ip,如果要监听本地,不对外服务,那么就是127.0.0.1;如 ...

  6. Swoole学习(三)Swoole之UDP服务器的创建

    环境:Centos6.4,PHP环境:PHP7 <?php //创建UCP服务器(UDP服务器相对于TCP服务器通信更可靠些) /** * $host 是swoole需要监听的ip,如果要监听本 ...

  7. Swoole学习(二)Swoole之TCP服务器的创建

    环境:Centos6.4,PHP环境:PHP7 <?php //创建TCP服务器 /** * $host 是swoole需要监听的ip,如果要监听本地,不对外服务,那么就是127.0.0.1;如 ...

  8. 【swoole】使用swoole简单实现TCP服务

    上一篇写到了如何在windows系统上面利用docker快速搭建swoole开发环境,接下来体验下swoole的使用 使用swoole实现tcp服务 <?php $serv = new Swoo ...

  9. Swoole学习(五)Swoole之简单WebSocket服务器的创建

    环境:Centos6.4,PHP环境:PHP7 服务端代码 <?php //创建websocket服务器 $host = '0.0.0.0'; $port = ; $ws = new swool ...

随机推荐

  1. 关于利用python进行验证码识别的一些想法

    转载:@小五义http://www.cnblogs.com/xiaowuyi 用python加“验证码”为关键词在baidu里搜一下,可以找到很多关于验证码识别的文章.我大体看了一下,主要方法有几类: ...

  2. Mac OS修改VSCode Go的默认缩进格式

    一.在VSCode中编写Go代码时,缩进是使用tab缩进,主要是由于以下两个方面. 1. Go官方提供的代码格式化工具gofmt默认是使用tab缩进,并且为8个字符宽度. 2. 并且在VSCode中, ...

  3. C 苟富贵

    时间限制 : 15000 MS   空间限制 : 524288 KB 问题描述 你最近买六合彩赚了很多钱,导致一个银行账户存不下了,于是你开设了 N 个账户,第 i 个账户里存有 Ai 元. 你的好友 ...

  4. Aplayer搭配Metingjs音乐插件的使用

    Aplayer搭配MetingJS音乐插件的使用 1. Aplayer和MetingJ的介绍 Aplayer官网文档:https://aplayer.js.org/#/ Metingjs官网文档:ht ...

  5. python:列表切片知识的总结

    列表的切片操作时对其中的单个或者多个索引对应元素的操作,具有如下特点: ①.切片区间是左闭右开区间 ②.切片的下标可以表示负数,-1表示倒数第一个数,-2表示倒数第二个数 ③.默认步长是1,可增加第三 ...

  6. STM32CubeMX的使用

    1.STM32CubeMX简介 STM32CubeMx软件是ST公司为STM32系列单片机快速建立工程,并快速初始化使用到的外设.GPIO等,大大缩短了我们的开发时间.同时,软件不仅能配置STM32外 ...

  7. 查看手机wifi密码

    方法一 手机共享wifi,获得二维码,之后解码获得密码. 二维码解吗工具: https://jiema.wwei.cn/ 方法二 手机扫描wifi共享的二维码后,会有提示信息,其中会显示出密码.

  8. mui在vue_cli上使用

    在main.js里添加 import mui from './assets/js/mui.js' 如果不添加下面会显示mui is not defined 报错 Vue.prototype.mui = ...

  9. DOS命令集

    1.ASSOC显示或修改文件扩展名关联.ASSOC [.ext[=[fileType]]]  .ext      指定跟文件类型关联的文件扩展名  fileType  指定跟文件扩展名关联的文件类型键 ...

  10. Docker基础修炼2--Docker镜像原理及常用命令

    通过前文的讲解对Docker有了基本认识之后,我们开始进入实战操作,本文先演示Docker三要素之镜像原理和相关命令. 本文的演示环境仍然沿用上一篇文章在本地Centos7中安装的环境,如果你本地没有 ...