c 多进程 共享内存下使用共享内存如何避免同时读写,又能保证效率

关于php的共享内存的使用和研究之外部存储 - 简书
关于php的共享内存的使用和研究之外部存储
上文中提到了针对php的共享内存方案的尝试,最终发现它并不适用于我的场景,如果想要兼容多进程或多线程并发读写的情况下可靠,一定要有适当的机制来保证资源的唯一性。
加锁肯定是想到的第一选择,对于每次共享内存的时候,先获取一个锁,只有获取成功了之后才允许进行读和写,这应该是最简单的方案,但是同步锁对性能的损耗也是比较大的。APC的user data cache的存储机制对数据要求严格正确,锁比较多,它的效率与本地的memcache相当。既然这样,不如把眼光投向业界,看看大牛们使用什么样的方案来解决这个问题。
原文链接:
laurance为了解决如下的两个问题,设计出了这个cache:
想让PHP进程之间共享一些简单的数据
希望非常高效的缓存一些页面
同时也是基于如下的经验假设:
对于一个应用来说, 同名的Cache键, 对应的Value, 大小几乎相当.
不同的键名的个数是有限的.
Cache的读的次数, 远远大于写的次数.
Cache不是数据库, 即使Cache失效也不会带来致命错误.
实现这个cache,关键是无锁化的设计. 根据laurance的说法,他解决读锁的方式是通过不加锁的读,然后CRC校验。
看了一下他代码的实现,是对key中存储的固定size的值进行了CRC的计算,然后把key中附带存储的crc信息和内容计算出来的crc信息进行校验。如果校验成功了,那么认为查询成功,如果校验失败了,那么认为查询失败。其实本质上这是一种使用CPU来换锁的方式,大部分的服务器是多核的,一旦加锁,对CPU是很大的浪费。下面这张图形象的表明了这一点:
yac_lock.png
这个是个不错的trick,能够解决的问题就是在多个进程频繁的写入的时候,可能导致的读出错不会带来错误的结果,因为一旦crc校验不通过,那么读出来的结果就是失效了。这显然比上一篇文章中的共享内存的读的方式要高明一些。不过根据我的观察,使用共享内存的方式,由于一直是向后不停的写入,出现被覆盖的概率几乎没有,而laurance这里之所以要校验,则是因为他会进行内存的回收和循环写入,这点在下文中会继续说明。
现在重点说说这个YAC的写入的问题,首先启动的时候key空间大小确定,可以通过配置来调整分配给存储key的大小,从而扩展key的个数。4M基本上相当于32768个Cache值。首先第一个很重要的点就是如何设计哈希方法来避免写入冲突,这里他使用的是双散列法的
对于小于4M的内存块的操作由于key不同,根据哈希出来的起始位置也不同。不同key之间冲突的概率,等同于哈希算法冲突的概率,这个还是比较低的。对于大的内存块,这里使用了segment-&pos指针来控制内存的分块。和共享内存扩展的实现方式还是比较类似了,反正就是一个pos指针,找得到就update,找不到就向后写。
那么如果发生冲突呢,laurance给出了一个例子:
比如A进程申请了40字节, B进程申请了60字节, 但是Pos只增加了60字节. 这个时候有如下几种情况:
A写完了数据, 返回成功, 但是B进程又写完了数据返回成功, 最终B进程的Cache种上了, 而A进程的被踢出了.
B进程写完了数据, 返回成功, A进程又写完了数据返回成功, 最终A进程的Cache种上了, B进程的被踢出.
A进程写一半, B进程写一半, 然后A进程又写一半, B进程又写一半, 都返回成功, 但最终, 缓存都失效.
可见, 最严重的错误, 就是A和B的缓存都失效, 但是Yac不会把错误数据返回给用户, 当下一次来查询Cache的时候, 因为存在crc校验, 所以都miss.
看到这儿终于明白了,并没有解决多进程写的问题,多进程的写还是可能会有冲突,不仅仅是单key的冲突,不同key之间也可能会有冲突。但是冲突了不怕,会通过校验的方式确保client端能够判断出来自己冲突了,这点对应用程序确实非常重要,因为这不是cache error,而仅仅是cache miss而已,这两种情况的严重程度和处理机制的确完全不同。
另外还有一个亮点是内存的循环分配,如果一个内存块用完了,那么可以重置pos,从而从头开始分配,有了这种机制,即使并发写导致pos一直后移,也不会出现内存耗尽的情况了,这确实是个不错的特性。
总结来看,yac两个不错的特性:
读的CRC校验,保证最严重是cache miss
写的pos重置,保证内存不被写满
但是针对我的使用场景,多并发情况下的同key的多写多读,它并没有很好的解决这个问题,而是比较适用于低频的用户数据的缓存,比如登陆用户的头像、昵称这类信息。拉取频次不高,miss了也能向后端请求。所以怎么办呢,只能继续进行求索。
ps:laurance在文章开头群嘲了一下APC的性能,相当于本地的memcache,结果文末贴出的性能对比,yac完全比不上apc。。有点莫名
Swoole table
接下来说说这两年在社区里面比较火,最近刚刚发布了内置协程2.0版本的swoole. github地址:
swoole table是swoole中的一个基于共享内存和锁实现的超高性能的并发数据结构,用来解决多进程、多线程数据共享和同步加锁的问题。这不就是我们苦苦寻觅的解决方案么?
先来看一下swoole table的常见的使用方式,首先它支持三种基本的类型:
swoole_table::TYPE_INT 整形字段
swoole_table::TYPE_FLOAT 浮点字段
swoole_table::TYPE_STRING 字符串字段
如果想要在各个进程之间共享高性能的本地数据,那么使用的范例如下:
// 新建swoole table,并且指定类型
$table = new swoole_table(1024);
$table-&column('id', swoole_table::TYPE_INT, 4);
$table-&column('name', swoole_table::TYPE_STRING, 64);
$table-&column('num', swoole_table::TYPE_FLOAT);
$table-&create();
// 新建swoole的server
$serv = new swoole_server('127.0.0.1', 9501);
//将table保存在serv对象上
$serv-&table = $
$serv-&on('receive', function ($serv, $fd, $from_id, $data) {
// 使用swoole table存储全局的数据
$ret = $serv-&table-&set($key, array('from_id' =& $data, 'fd' =& $fd, 'data' =& $data));
// 这里需要注意的就是一定要在server启动之前创建swoole table,从而保证它能够被全局共享
$serv-&start();
如果只是你自己的一个进程在不同的请求之间共享高性能的本地数据,那么使用的范例如下:
class LocalSwooleTable {
private static $_swooleT// 静态变量,单个进程内共享
const SWOOLE_TABLE_SET_FAILED = -1001;
const SWOOLE_TABLE_GET_FAILED = -1002;
// swoole table初始化
private function __construct() {
//预估数据量 100个服务,每个长度30 需要3000个字节,这里申请64k
self::$_swooleTable = new \swoole_table(65536);
self::$_swooleTable-&column('ip',\swoole_table::TYPE_STRING, 64);
self::$_swooleTable-&column('port',\swoole_table::TYPE_INT, 4);
self::$_swooleTable-&column('timestamp',\swoole_table::TYPE_INT, 4);
self::$_swooleTable-&column('bTcp',\swoole_table::TYPE_INT, 4);
self::$_swooleTable-&create();
// 获取单个swoole的实例
public static function getInstance() {
if(self::$_swooleTable) {
return self::$_swooleT
new LocalSwooleTable();
return self::$_swooleT
// 获取唯一的实例
$swooleTableIns = LocalSwooleTable::getInstance();
$key = "sample";
$routeInfo['timestamp'] = time();
$routeInfo['ip'] = '10.25.22.33';
$routeInfo['port'] = 1000;
$routeInfo['bTcp'] = 1;
// 设置swoole table中的内容
$flag = $swooleTableIns-&set($key,$routeInfo);
// 获取swoole table中的内容
$routeInfo = $swooleTableIns-&get($key);
本来,第一种方式应该是我们最好的选择,但是因为我们使用了TSF框架(或者任何不是自己从头裸写swoole的框架),都不会把创建server这一步暴露到业务代码中,这就给我们使用全局的swoole的table带来了很大的难度。换句话说,知道好用,但是就是业务用起来非常的不方便,不具备业务扩展性。
所以无奈之下,我们还是选取了第二种方案,从性能上面来讲的话,确实是有提升的,不好的地方就是存储资源浪费了一些,每个进程都用了专属自己的swoole table,这当然是无奈之举。还是希望能够之后通过一些改造,把全局的swoole table这种能力能够开放出来。
下午5.28.17.png
基本上访问一次是0.03ms,这个性能还是比较突出的。
工程师一枚,喜欢折腾,爱旅行,热爱生活,对世界充满好奇。
下文:关于php的共享内存的使用和研究之外部存储 关于php的共享内存的使用和研究之深入剖析swoole table 最近遇到一个场景,服务寻址的时候,需要请求远程的服务,获取一批可用的ip和端口地址及其权重。根据权重和随机算法选择最合适的一个服务地址,进行请求。由于服务地...
1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语法,集合的语法,io的语法,虚拟机方面的语法。 1、一个&.java&源文件中是否可以包括多个类(不是内部类)?有什么限制? 可以有多个类,但只能有一个publ...
上文:关于php的共享内存的使用和研究之由起关于php的共享内存的使用和研究之外部存储 话说回来,究竟swoole的底层是怎么做到了使用行锁,来实现进程访问冲突解决与高性能的呢?这里确实值得研究一下。 首先来看一下swooletable中用来存储的基本数据结构swTable...
前言本文主要说明在Linux环境上如何使用共享内存。阅读本文可以帮你解决以下问题: 什么是共享内存和为什么要有共享内存? 如何使用mmap进行共享内存? 如何使用XSI共享内存? 如何使用POSIX共享内存? 如何使用hugepage共享内存以及共享内存的相关限制如何配置?...
一. Java基础部分......................................................................................................21、一个&.java&源文件中是否可以包括多个...
鲁迅先生说:“我向来不惮以最坏的恶意揣测中国人。”先生对中国传统文化中的瞒和骗深恶痛绝,观察社会观察生活时往往抱着怀疑主义的态度,透过粉饰装修过的外表直达其黑暗罪恶的本质,从不相信任何冠冕堂皇的表演。而在我们现实生活中,有太多太多见不得光的一面,因为沉默的大多数而湮没,我们...
刚刚看到一个关于大码模特的文章,突然想到自己。本人并不是胖,而是瘦。听到太多人说,你怎么这么瘦啊。这是我最不喜欢的一句话,非常不喜欢别人说我瘦。 看到这你该翻白眼了。 我有个室友,说你太瘦了吧,一边说一边摇头叹气。当时真想冲上去大喊,我吃得最多,饭量最大,又没减肥,爬山跑步...
导语 旅行不仅可以让我们见世界,见自己,还可以帮助我们认识到身边的那个人。彼此是否适合过一生,往往在旅途中明晰。 -----漫游家,心随自然 日语里有个词叫成田分手,就是因为很多新婚夫妇蜜月旅行回来,在成田机场就直接分手了。But why? 据说“恋人婚前应该至少旅行一次”...
昨天,以前跟妈妈关系很好的一个阿姨(后来搬家了)到西安来游玩了。晚上陪她们在回民街吃了顿饭,然后小逛了一下钟楼。 这个阿姨姓杨,就叫她杨姨,距上一次见她都过去十二三年了。那还是在高考完后,填报志愿的时候在她家聚了一下,杨姨和叔叔非常热心。杨叔在政府工作,在帮我争取高考前十的...
作者:思文扫地 (TalentGuide签约作者,没有高大上的知识传授,只有接地气的感悟分享。) 01星座与职业价值逻辑关系 前两天带部门新员工Y出差,途中我问他,当初为什么选择进公司?Y说,他之前在北京的某创业公司实习,喜欢那种开放式的工作环境,团队氛围很友好。但是家里人...c语言多进程多线程编程 - 注册会计-
当前位置:
c语言多进程多线程编程
馆藏:11600
下载此文档
同系列文档
Baidu Button END -->
官方公众微信新手园地& & & 硬件问题Linux系统管理Linux网络问题Linux环境编程Linux桌面系统国产LinuxBSD& & & BSD文档中心AIX& & & 新手入门& & & AIX文档中心& & & 资源下载& & & Power高级应用& & & IBM存储AS400Solaris& & & Solaris文档中心HP-UX& & & HP文档中心SCO UNIX& & & SCO文档中心互操作专区IRIXTru64 UNIXMac OS X门户网站运维集群和高可用服务器应用监控和防护虚拟化技术架构设计行业应用和管理服务器及硬件技术& & & 服务器资源下载云计算& & & 云计算文档中心& & & 云计算业界& & & 云计算资源下载存储备份& & & 存储文档中心& & & 存储业界& & & 存储资源下载& & & Symantec技术交流区安全技术网络技术& & & 网络技术文档中心C/C++& & & GUI编程& & & Functional编程内核源码& & & 内核问题移动开发& & & 移动开发技术资料ShellPerlJava& & & Java文档中心PHP& & & php文档中心Python& & & Python文档中心RubyCPU与编译器嵌入式开发驱动开发Web开发VoIP开发技术MySQL& & & MySQL文档中心SybaseOraclePostgreSQLDB2Informix数据仓库与数据挖掘NoSQL技术IT业界新闻与评论IT职业生涯& & & 猎头招聘IT图书与评论& & & CU技术图书大系& & & Linux书友会二手交易下载共享Linux文档专区IT培训与认证& & & 培训交流& & & 认证培训清茶斋投资理财运动地带快乐数码摄影& & & 摄影器材& & & 摄影比赛专区IT爱车族旅游天下站务交流版主会议室博客SNS站务交流区CU活动专区& & & Power活动专区& & & 拍卖交流区频道交流区
白手起家, 积分 197, 距离下一级还需 3 积分
论坛徽章:0
多个进程环境下,所有进程既是消费者,又是生产者。
那么如何设计会使得共享内存的利用效率最好呢?
假定如下的结构体,当然仅仅写了表示需要读取的数据和写入的数据类型:
struct shm_store
& &char in[1024];& && && && &//写入的数据
& &char out[1024];& && && &//读取的数据
创建一个由1024个这种结构体组成的共享内存
白手起家, 积分 134, 距离下一级还需 66 积分
论坛徽章:1
利用效率的高低,完全和你具体如何使用有关吧。
巨富豪门, 积分 24028, 距离下一级还需 15972 积分
论坛徽章:59
& & 你这个很简单啊, 结构大小都一样,就是一个环形数组。
如果有原子加/原子减函数,可以使用无锁结构
白手起家, 积分 197, 距离下一级还需 3 积分
论坛徽章:0
本帖最后由 nameofhsw 于
12:22 编辑
folklore 发表于
回复 1# nameofhsw
你是指使用环线数组,那怎么保证不会多个进程同时读取数组其中一项呢?
如果不使用C++,C没有原子操作吧
巨富豪门, 积分 24028, 距离下一级还需 15972 积分
论坛徽章:59
& & 原子加的话, 加一是原子的,所以每次加1都指向下一个结点啊。
下一个结点能相同么~
要实现无锁结构, 要额外的缓存支持。因为ir -1=iw时不能写,
iw -1=ir时不能读。
家境小康, 积分 1417, 距离下一级还需 583 积分
论坛徽章:0
本帖最后由 Hugo801122 于
13:03 编辑
多个进程环境下,所有进程既是消费者,又是生产者。
那么如何设计会使得共享内存的利用效率最好呢?
假定如下的结构体,当然仅仅写了表示需要读取的数据和写入的数据类型:
struct shm_store
& &char in[1024];& && && && &//写入的数据
& &char out[1024];& && && &//读取的数据
创建一个由1024个这种结构体组成的共享内存
----利用效率高不高看自己怎么设计的,和内存本身没多大关系啊。
北京盛拓优讯信息技术有限公司. 版权所有 京ICP备号 北京市公安局海淀分局网监中心备案编号:22
广播电视节目制作经营许可证(京) 字第1234号
中国互联网协会会员&&联系我们:
感谢所有关心和支持过ChinaUnix的朋友们
转载本站内容请注明原作者名及出处新手园地& & & 硬件问题Linux系统管理Linux网络问题Linux环境编程Linux桌面系统国产LinuxBSD& & & BSD文档中心AIX& & & 新手入门& & & AIX文档中心& & & 资源下载& & & Power高级应用& & & IBM存储AS400Solaris& & & Solaris文档中心HP-UX& & & HP文档中心SCO UNIX& & & SCO文档中心互操作专区IRIXTru64 UNIXMac OS X门户网站运维集群和高可用服务器应用监控和防护虚拟化技术架构设计行业应用和管理服务器及硬件技术& & & 服务器资源下载云计算& & & 云计算文档中心& & & 云计算业界& & & 云计算资源下载存储备份& & & 存储文档中心& & & 存储业界& & & 存储资源下载& & & Symantec技术交流区安全技术网络技术& & & 网络技术文档中心C/C++& & & GUI编程& & & Functional编程内核源码& & & 内核问题移动开发& & & 移动开发技术资料ShellPerlJava& & & Java文档中心PHP& & & php文档中心Python& & & Python文档中心RubyCPU与编译器嵌入式开发驱动开发Web开发VoIP开发技术MySQL& & & MySQL文档中心SybaseOraclePostgreSQLDB2Informix数据仓库与数据挖掘NoSQL技术IT业界新闻与评论IT职业生涯& & & 猎头招聘IT图书与评论& & & CU技术图书大系& & & Linux书友会二手交易下载共享Linux文档专区IT培训与认证& & & 培训交流& & & 认证培训清茶斋投资理财运动地带快乐数码摄影& & & 摄影器材& & & 摄影比赛专区IT爱车族旅游天下站务交流版主会议室博客SNS站务交流区CU活动专区& & & Power活动专区& & & 拍卖交流区频道交流区
白手起家, 积分 197, 距离下一级还需 3 积分
论坛徽章:0
多个进程环境下,所有进程既是消费者,又是生产者。
那么如何设计会使得共享内存的利用效率最好呢?
假定如下的结构体,当然仅仅写了表示需要读取的数据和写入的数据类型:
struct shm_store
& &char in[1024];& && && && &//写入的数据
& &char out[1024];& && && &//读取的数据
创建一个由1024个这种结构体组成的共享内存
白手起家, 积分 134, 距离下一级还需 66 积分
论坛徽章:1
利用效率的高低,完全和你具体如何使用有关吧。
巨富豪门, 积分 24028, 距离下一级还需 15972 积分
论坛徽章:59
& & 你这个很简单啊, 结构大小都一样,就是一个环形数组。
如果有原子加/原子减函数,可以使用无锁结构
白手起家, 积分 197, 距离下一级还需 3 积分
论坛徽章:0
本帖最后由 nameofhsw 于
12:22 编辑
folklore 发表于
回复 1# nameofhsw
你是指使用环线数组,那怎么保证不会多个进程同时读取数组其中一项呢?
如果不使用C++,C没有原子操作吧
巨富豪门, 积分 24028, 距离下一级还需 15972 积分
论坛徽章:59
& & 原子加的话, 加一是原子的,所以每次加1都指向下一个结点啊。
下一个结点能相同么~
要实现无锁结构, 要额外的缓存支持。因为ir -1=iw时不能写,
iw -1=ir时不能读。
家境小康, 积分 1417, 距离下一级还需 583 积分
论坛徽章:0
本帖最后由 Hugo801122 于
13:03 编辑
多个进程环境下,所有进程既是消费者,又是生产者。
那么如何设计会使得共享内存的利用效率最好呢?
假定如下的结构体,当然仅仅写了表示需要读取的数据和写入的数据类型:
struct shm_store
& &char in[1024];& && && && &//写入的数据
& &char out[1024];& && && &//读取的数据
创建一个由1024个这种结构体组成的共享内存
----利用效率高不高看自己怎么设计的,和内存本身没多大关系啊。
北京盛拓优讯信息技术有限公司. 版权所有 京ICP备号 北京市公安局海淀分局网监中心备案编号:22
广播电视节目制作经营许可证(京) 字第1234号
中国互联网协会会员&&联系我们:
感谢所有关心和支持过ChinaUnix的朋友们
转载本站内容请注明原作者名及出处[求助]windows 用 createmappfile 共享内存,多进程读写这个共享内存,需要用MUTEX加锁吗?
亲自测试了一下,貌似也没有问题。假如我一进程对共享内存的buffer[1024]进行memcpy,另一个进程对共享内存读取,这样需要不需要加锁?共享内存的地址都是通过
MapViewOfFile得到的。利用CreateMappingFile 和MapViewOfFile这种方式共享内存的原理又是什么呢?
支付方式:
最新回复 (4)
只读不用锁,有写的话必须加锁
只读不用锁,有写的话必须加锁
赏金两元,& 大表哥分我一块吧.
看你这块内存存储成什么数据结构,一进程读,一进程写可以不用锁。
buffer[1024]一读一写也必须加锁,& 不锁显然数据会乱
1.请先关注公众号。
2.点击菜单"更多"。
3.选择获取下载码。

我要回帖

更多关于 共享内存多进程写 的文章

 

随机推荐