原因
进程作为程序执行过程中资源分配的基本单位,拥有独立的地址空间,同一进程的线程可以共享本进程的全局变量,静态变量等数据和地址空间,但进程之间资源相互独立。
由于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
。
解决方法:
swoole为我们提供了两种有效的解决方法,都是基于多进程内存型数据库,代替单进程PHP变量来存储fd
。
第一种为:swoole_redis
,特点是使用简单,跟PHP原生的redis
用法几乎一致。
第二种为:swoole_table
,这是swoole官方研制的一款内存型数据库,比redis
的可扩展性要强许多,单机器的情况下牛牛推荐大家使用这种方法。
Swoole_Tbale
swoole_redis
没什么好谈的,因为redis
都是个老活了,用法都一个鸟样。
下面我们就重点搞下swoole_table
的用法。
一波官方说明袭来:
Table
一个基于共享内存和锁实现的超高性能,并发数据结构。用于解决多进程/多线程数据共享和同步加锁问题。
请谨慎使用数组方式读写Table, 建议使用文档中提供的API来进行操作
数组方式取出的SwooleTableRow对象为一次性对象, 请勿依赖其进行过多操作
优势
性能强悍,单线程每秒可读写200万次
应用代码无需加锁,Table内置行锁自旋锁&#x