swoole 多进程共享数据
进程作为程序执行过程中资源分配的基本单位,拥有独立的地址空间,同一进程的线程可以共享本进程的全局变量,静态变量等数据和地址空间,但进程之间资源相互独立.由于PHP语言不支持多线程,因此Swoole使用多进程模式,再多进程模式下就存在进程内存隔离,进程间通信与数据共享问题.
swoole中master主进程会创建manager管理进程和reactor线程,真正的工作进程为worker进程. manager是创建和管理worker进程,reactor进程测试监听socket,接受数据任务,发送给worker进程去工作,因此所有业务逻辑最终都是在worker进程中进行的,worker进程之间的数据共享与通信必不可少.
swoole中 设置选项worker_num设置 启动的worker进程数,默认设置为CPU核数
$server = new swoole_server('127.0.0.1',9898);
$server->set(array(
'worker_num' => 4, //设置启动的Worker进程数。
));
如上面说描述,进程存在进程隔离:
$fds = array();
$server->on('connect', function ($server, $fd){
echo "connection open: {$fd}\n";
global $fds;
$fds[] = $fd;
var_dump($fds);
});
$fds虽然是全局变量,但是只在但前的进程内有效,swoole服务器底层会创建多个worker进程,此处打印出来的只有部分连接的fd,本文讲简述两种解决方案的简单示例:
1.外部存储服务 : Redis
作为内存数据库redis 无太多IO等待,并且读写速度快
示例代码:以简易聊天室websocket服务 swoole_websocket_server为例
1 $ws = new swoole_websocket_server("0.0.0.0", 9999);
$redis = new \Redis();
$redis->connect('127.0.0.1', 6379);
$ws->set(array(
'daemonize' => false,
'worker_num' => 4,
));
//监听WebSocket连接打开事件
$ws->on('open', function ($ws, $request) use($redis) {
var_dump($request->fd, $request->get, $request->server);
//记录连接
$redis->sAdd('fd', $request->fd);
$count = $redis->sCard('fd');
var_dump($count);
$ws->push($request->fd, 'hello, welcome ☺ 当前'.$count.'人连接在线');
});
//监听WebSocket消息事件
$ws->on('message', function ($ws, $frame) use($redis) {
$fds = $redis->sMembers('fd');
$data = json_decode($frame->data,true);
if($data['type'] ==1 ){
$redis->set($frame->fd,json_encode(['fd'=>$frame->fd,'user'=>$data['user']]));
//通知所有用户新用户上线
$fds = $redis->sMembers('fd');$users=[];
$i=0;
foreach ($fds as $fd_on){
$info = $redis->get($fd_on);
$users[$i]['fd'] = $fd_on;
$users[$i]['name'] = json_decode($info,true)['user'];
$message = "欢迎 <b style='color: darkmagenta ;'>".$data['user']."</b> 进入聊天室";
$push_data = ['message'=>$message,'users'=>$users];
$ws->push($fd_on,json_encode($push_data));
$i++;
}
}else if($data['type'] ==2){
if($data['to_user'] == 'all'){
foreach ($fds as $fd){
$message = "<b style='color: crimson'>".$data['from_user']." say:</b> ".$data['msg'];
$push_data = ['message'=>$message];
$ws->push($fd,json_encode($push_data));
}
}
}
echo "Message: {$frame->data}\n";
});
//监听WebSocket连接关闭事件
$ws->on('close', function ($ws, $fd) use ($redis){
$redis->sRem('fd',$fd);
$fds = $redis->sMembers('fd');
$i=0;
foreach ($fds as $fd_on){
$user = json_decode($redis->get($fd),true)['user'];
$info = $redis->get($fd_on);
$users[$i]['fd'] = $fd_on;
$users[$i]['name'] = json_decode($info,true)['user'];
$message = "<b style='color: blueviolet'>".$user."</b> 离开聊天室了";
$push_data = ['message'=>$message,'users'=>$users];
$ws->push($fd_on,json_encode($push_data));
$i++;
}
echo "client-{$fd} is closed\n";
});
2.共享内存拓展:swoole_table
swoole_table是swoole官方提供的基于共享内存和锁实现的超高性能冰饭数据结构.swoole_table在swoole1.7.5版本后可用.
目前swoole只支持3种类型:
swoole_table::TYPE_INT 整形字段
swoole_table::TYPE_FLOAT浮点字段
swoole_table::TYPE_STRING 字符串字段
函数方法:
column() :给内存表增加一列 参数:字段名,字段类型,字节数
$table->column('id', swoole_table::TYPE_INT, 4);
create():基于前一步对表结构的创建,执行创建表.
set() :设置行的数据(key-value的方式) 参数: 数据的key,数据的值(必须数组,键名必须与字段定义的$name相同)
$table->set($fd, ['id'=>1]);
get() :获取一行数据 参数:数据的key
$table->get($fd);
del() :删除一行数据 参数:数据的key
$table->del($fd);
lock():锁定整个表
unlock():释放锁
lock/unlock 必须成对出现,否则会发生死锁.
示例代码: 还是上面的websocket服务为例
class WebSocketServer {
private $server;
public function __construct()
{
$this->server = new swoole_websocket_server("0.0.0.0",9988);
$this->server->set(array(
'daemonize' => false,
'worker_num' => 4,
));
//内存表
$fd_table = new swoole_table( 1024 );
$fd_table->column( "user",swoole_table::TYPE_STRING, 30 );
$fd_table->column( "time", swoole_table::TYPE_STRING, 20 );
$fd_table->create();
$user_table = new swoole_table(1024);
$user_table->column("fd",swoole_table::TYPE_INT,8);
$user_table->create();
$this->server->fd = $fd_table;
$this->server->user = $user_table;
//启动开始
$this->server->on('Start',[$this,'onStart']);
//与onStart同级
$this->server->on('workerStart',[$this,'onWorkerStart']);
//webSocket open 连接触发回调
$this->server->on('open',[$this,'onOpen']);
//webSocket send 发送触发回调
$this->server->on('message', [$this, 'onMessage']);
//webSocket close 关闭触发回调
$this->server->on('Close', [$this, 'onClose']);
//tcp连接 触发 在 webSocket open 之前回调
$this->server->on('Connect', [$this, 'onConnect']);
//tcp 模式下(eg:telnet ) 发送信息才会触发 webSocket 模式下没有触发
$this->server->on('Receive', [$this, 'onReceive']);
// 服务开启
$this->server->start();
}
public function onStart( $server)
{
echo "Start\n";
}
public function onWorkerStart($server,$worker_id)
{
//判断是worker进程还是 task_worker进程 echo 次数 是worker_num+task_worker_num
if($worker_id<$server->setting['worker_num']){
echo 'worder'.$worker_id."\n";
}else{
echo 'task_worker'.$worker_id."\n";
}
// echo "workerStart{$worker_id}\n";
}
public function onOpen( $server,$request)
{
$this->server->fd->set($request->fd,['user'=>'']);
echo "server: handshake success with fd{$request->fd}\n";
$count = count($server->connections);
$server->push($request->fd, 'hello, welcome ☺ 当前'.$count.'人连接在线');
}
public function onMessage( $server,$frame)
{
echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
$data = json_decode($frame->data,true);
if($data['type'] ==1 ){
$server->fd->set($frame->fd,['user'=>$data['user']]);
//通知所有用户新用户上线
foreach($server->connections as $key => $fd) {
$server->push($fd, "欢迎 <b style='color: darkmagenta ;'>".$data['user']."</b> 进入聊天室");
}
}else if($data['type'] ==2){
if($data['to_user'] == 'all'){
foreach($server->connections as $key => $fd) {
$server->push($fd, "<b style='color: crimson'>".$data['from_user']." say:</b> ".$data['msg']);
}
}
}
}
public function onConnect( $server, $fd, $from_id ) {
echo "Client {$fd} connect\n";
echo "{$from_id}\n";
}
public function onReceive( $server, $fd, $from_id, $data ) {
echo "Get Message From Client {$fd}:{$data}\n";
}
public function onClose($server, $fd)
{
echo "Client {$fd} close connection\n";
foreach($server->connections as $key => $on_fd) {
$user = $server->fd->get($fd)['user'];
$server->push($on_fd, "<b style='color: blueviolet'>".$user."</b> 离开聊天室了");
}
}
}
new WebSocketServer();
swoole 多进程共享数据的更多相关文章
- Nodejs中cluster模块的多进程共享数据问题
Nodejs中cluster模块的多进程共享数据问题 前述 nodejs在v0.6.x之后增加了一个模块cluster用于实现多进程,利用child_process模块来创建和管理进程,增加程序在多核 ...
- Android开发中多进程共享数据
# 背景 最近在工作中遇到一个需求,需要在接收到推送的时候将推送获得的数据存起来,以供app启动时使用.我们会认为这不是So easy吗?只要把数据存到SharedPreferences中,然后让ap ...
- 多进程共享数据,真正的通信Manager
Managers A manager object returned by Manager() controls a server process which holds Python objects ...
- Python 进程之间共享数据
最近遇到多进程共享数据的问题,到网上查了有几篇博客写的蛮好的,记录下来方便以后查看. 一.Python multiprocessing 跨进程对象共享 在mp库当中,跨进程对象共享有三种方式,第一种 ...
- Swoole 中使用 Table 内存表实现进程间共享数据
背景 在多进程模式下进程之间的内存是相互隔离的,在一个工作进程中的全局变量和超全局变量,在另一个工作进程中是无法读取和操作的. 如果只有一个工作进程,则不存在进程隔离问题,可以使用全局变量和超全局变量 ...
- python并发编程之多进程(三):共享数据&进程池
一,共享数据 展望未来,基于消息传递的并发编程是大势所趋 即便是使用线程,推荐做法也是将程序设计为大量独立的线程集合 通过消息队列交换数据.这样极大地减少了对使用锁定和其他同步手段的需求, 还可以扩展 ...
- 通过 Swoole\Table 实现 Swoole 多进程数据共享
第三方存储媒介 前面我们介绍了基于 Swoole 的 Process 及 Process\Pool 模块在 PHP 中实现多进程管理,但是多进程模式下进程间是相互隔离的,无法共享数据和变量,即便是通过 ...
- python 进程间共享数据 (二)
Python中进程间共享数据,除了基本的queue,pipe和value+array外,还提供了更高层次的封装.使用multiprocessing.Manager可以简单地使用这些高级接口. Mana ...
- python 进程间共享数据 (一)
def worker(num, mystr, arr): num.value *= 2 mystr.value = "ok" for i in range(len(arr)): a ...
随机推荐
- TypeError: 'generator' object is not subscriptable
TypeError: 'generator' object is not subscriptable 生成器对象不可以带下标 def get_row(self,row_no): if not isin ...
- JPA Example查询
//创建查询条件数据对象 Customer customer = new Customer(); customer.setAddress("河南省郑州市"); customer.s ...
- MySQL-第八篇MySQL内置函数
1.根据函数对多行数据的处理方式,可以分为: 1>单行函数:对每行输入值进行单独计算,每行得到一个计算结果返回给用户. 2>多行函数:聚集函数.分组函数,主要用于完成一些统计功能.对多行 ...
- (vue.js)axios interceptors 拦截器中添加headers 属性
(vue.js)axios interceptors 拦截器中添加headers 属性:http://www.codes51.com/itwd/4282111.html 问题: (vue.js)axi ...
- bzoj3218 a + b Problem(网络流+主席树)
$ans=\sum_{color_i=black}\ b_i+\sum_{color_i=white}\ w_i-\sum_{i=abnormal}\ p_i$ 把它转化一下 $ans=\sum_{i ...
- PHP实现上传文件到服务器
<?php /**************************** *** 功能:上传文件到服务器 ****************************/ session_start() ...
- JS中的匿名函数、回调函数、匿名回调函数
工欲善其事必先利其器 在学习JavaScript设计模式一书时,遇到了“匿名回调函数”这个概念,有点疑惑,查找了些资料重新看了下函数的相关知识点之后,对这个概念有了认识.九层之台,起于垒土.在熟悉这一 ...
- SIP UserAgent (B2BUA client)——libosip2 libeXosip2
1. libosip2 libeXosip2 http://www.antisip.com/download/exosip2/ Features:--------eXosip2 has support ...
- 服务器处理 json 数据
今天做小程序后端,需要处理 json 数据,我用的 express 框架,无法直接处理,需要进行 json 提取,网上找了一堆,发现json 四种解析格式,在此记录一下 www-form-urlenc ...
- 初学Java 九九乘法表
public class MultiplicationTable { public static void main(String[] args) { System.out.println(" ...