php简单使用shmop函数创建共享内存减少服务器负载
在之前的一篇博客[了解一下共享内存的概念及优缺点]已经对共享内存的概念做了说明。下面就来简单使用共享内存(其实也可以用其他工具,比如redis)
PHP做内存共享有两套接口。一个是shm,它实际上是变量共享,会把对象变量序列化后再储存。使用起来倒是挺方便,但是序列化存储对于效率优先的内存访问操作而言就没啥意义了。另外一个是shmop,它是Linux和Windows通用的,不过功能上比shm弱了一些,在 Linux 上,这些函数直接是通过调用 shm* 系列的函数实现,而 Winodows 上也通过对系统函数的封装实现了同样的调用。我这里先用的是shmop。
要创建共享内存段需要使用函数shmop,那么前提需要开启扩展,可以参考[给PHP开启shmop扩展实现共享内存].
shmop主要函数
shmop_open (创建或打开共享内存块)、shmop_write (向共享内存块中写入数据)、shmop_read (从共享内存块中读取数据)、shmop_size (获取共享内存块的大小)、shmop_close (关闭共享内存块)、shmop_delete (删除共享内存块)
<?php
//创建一块共享内存
$shm_key = 0x4337b101;
$shm_id = @shmop_open($shm_key, 'c', , );
//读取并写入数据
$data = shmop_read($shm_id, , );
shmop_write($shm_id, json_encode($data), );
$size = shmop_size($shm_id); //获取内存中实际数据占用大小
//关闭内存块,并不会删除共享内存,只是清除 PHP 的资源
shmop_close($shm_id);
shmop_open(创建内存段)
该函数中出现的第一个事物是系统 ID 参数。这是标识系统中的共享内存段的数字。第二个参数是访问模式,它非常类似于 fopen 函数的访问模式。您可以在 4 种不同的模式下访问一个内存段:
模式 “a”,它允许您访问只读内存段,只读访问
模式 “w”,它允许您访问可读写的内存段,读写
模式 “c”,它创建一个新内存段,或者如果该内存段已存在,尝试打开它进行读写
模式 “n”,它创建一个新内存段,如果同样 key 的已存在,则会创建失败,这是为了安全使用共享内存考虑。
第三个参数是内存段的权限。您必须在这里提供一个八进制值。
第四个参数提供内存段大小,以字节为单位。由于使用的共享内存片段是固定长度的,在存储和读取的时候要计算好数据的长度,不然可能会写入失败或者读取空值。。
请注意,此函数返回一个 ID 编号,其他函数可使用该 ID 编号操作该共享内存段。这个 ID 是共享内存访问 ID,与系统 ID 不同,它以参数的形式传递。请注意不要混淆这两者。如果失败,shmop_open 将返回 FALSE。在创建内存块时建议key参数用常量而不用变量,否则很有可能造成内存泄露。
shmop_write(向内存段写入数据)
这个函数类似于 fwrite 函数,后者有两个参数:打开的流资源(由 fopen 返回)和您希望写入的数据。shmop_write 函数也执行此任务。
第一个参数是 shmop_open 返回的 ID,它识别您操作的共享内存块。第二个参数是您希望存储的数据,最后的第三个参数是您希望开始写入的位置。默认情况下,我们始终使用 0 来表示开始写入的位置。请注意,此函数在失败时会返回 FALSE,在成功时会返回写入的字节数。
shmop_read(从内存段读取数据)
从共享内存段读取数据很简单。您只需要一个打开的内存段和 shmop_read 函数。此函数接受一些参数,工作原理类似于 fread。
请留意这里的参数。shmop_read 函数将接受 shmop_open 返回的 ID,我们已知道它,不过它还接受另外两个参数。第二个参数是您希望从内存段读取的位置,而第三个是您希望读取的字节数。第二个参数可以始终为 0,表示数据的开头,但第三个参数可能存在问题,因为我们不知道我们希望读取多少字节。
这非常类似于我们在 fread 函数中的行为,该函数接受两个参数:打开的流资源(由 fopen 返回)和您希望从该流读取的字节数。使用 filesize 函数(它返回一个文件中的字节数)来完整地读取它。
shmop_size(返回内存段数据实际大小)
比如,我们开辟了一个长度为100字节的内存空间,但是实际存入的数据长度仅仅90,那么使用shmop_size返回的值就是90.
shmop_delete(删除内存段)
该函数仅接受一个参数:我们希望删除的共享内存 ID,这不会实际删除该内存段。它将该内存段标记为删除,因为共享内存段在有其他进程正在使用它时无法被删除。shmop_delete 函数将该内存段标记为删除,阻止任何其他进程打开它。要删除它,我们需要关闭该内存段。在创建内存块时建议key参数用常量而不用变量,否则很有可能造成内存泄露。
shmop_close(关闭内存段)
我们在对内存段进行读取和写入,但完成操作后,我们必须从它解除,这非常类似于处理文件时的 fclose 函数。打开包含一个文件的流并在其中读取或写入数据后,我们必须关闭它,否则将发生锁定。
简单测试结果查看
我是在LNMP环境下操作的,如果你也和我一样,在执行完简单的操作之后,可以使用linux命令查看一下地址和占用大小
# ipcs -m
[root@bogon ~]# ipcs -m ------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 gdm dest
0x00000000 gdm dest
0x4337b101 nobody
命令说明
key :共享内存的唯一的key值,共享内存通过该key来判断你读取的是哪一块内存。
shmid:当使用key来获取内存时,你获得的是这个id的值。它作为你操作内存块的标识。
owner:创建该共享内存块的用户
perms:该共享内存的读写权限,8禁止,可以是777,与文件的读写权限一致。
bytes:该内存块的大小
nattch:连接该内存块的进程数
status:当前状态,如:dest,即将删除等。
项目实际应用小案例
/**
* 将领技能
*/
class Generalskill_model extends CI_Model { private $_memory_key = 0x4337b001; //共享内存地址key
private $_memory_size = ; //开辟共享内存大小 //最好根据实际数据长度大小定义。 public function __construct() {
parent::__construct();
} public function get_skill_list() {
$data = [];
$shmid = @shmop_open($this->_memory_key, 'a', , $this->_memory_size); if ($shmid === FALSE) {
$shmid = @shmop_open($this->_memory_key, 'c', , $this->_memory_size);
$data = $this->return_skill_list();
shmop_write($shmid, json_encode($data), );
@shmop_close($shmid); return $data;
}
$data = json_decode(preg_replace('/[\x00-\x1F\x80-\x9F]/u', '', trim(shmop_read($shmid, , $this->_memory_size))), true);
@shmop_close($shmid);
return $data; } public function return_skill_list() { //这里是一个超大的数组,其实就是把这个数组json化,然后存入共享内存段。 其实可以用redis等其他缓存...这里我就是为了不用redis等其他nosql才用的shmop
return array (
=>
array ('id' => '','animation' => '','skill_type' => '','power_type' => '','site' => '','type' => '','paramete' => '','paramete2' => '','paramete3' => '','chance' => '','ratio' => '',
),
=>
array ('id' => '','animation' => '','skill_type' => '','power_type' => '','site' => '','type' => '','paramete' => '','paramete2' => '','paramete3' => '','chance' => '','ratio' => '',
),..........................................
当然你要考虑的是,如果数据更新的话,那么内存段也要删除,并且更新数据......................通过shmop_delete可以删除 。这就需要你们自己根据项目应用来考虑了
还有就是我这里只是为了简单的读,并没有出现复杂的读写,否则可能会出现进程互斥等意想不到的冲突~如果复杂,那么就可以考虑信号量了~
如果你在项目中遇到主从场景。可以参考这篇文章 http://tubaluer.iteye.com/blog/1349797
php简单使用shmop函数创建共享内存减少服务器负载的更多相关文章
- JNI创建共享内存导致JVM terminated的问题解决(segfault,shared memory,内存越界,内存泄漏,共享内存)
此问题研究了将近一个月,最终发现由于JNI不支持C中创建共享内存而导致虚拟机无法识别这块共享内存,造成内存冲突,最终虚拟机崩溃. 注意:JNI的C部分所使用的内存也是由JVM创建并管理的,所以C创建了 ...
- 排查nginx、tomcat内存和服务器负载之后
最近客户现在提出系统访问非常慢,需要优化提升访问速度,在排查了nginx.tomcat内存和服务器负载之后,判断是数据库查询速度慢,进一步排查发现是因为部分视图和表查询特别慢导致了整个系统的响应时间特 ...
- 创建共享内存函数CreateFileMapping()详解
测试创建和打开文件映射的时候老是得到"句柄无效"的错误, 仔细看了MSDN以后才发觉是函数认识不透, 这里把相关的解释翻译出来 HANDLE CreateFileMapping( ...
- 给PHP开启shmop扩展实现共享内存
在项目开发中,想要实现PHP多个进程之间共享数据的功能,让客户端连接能够共享一个状态,需要开启共享内存函数shmop.如果预期考虑会遇到这方面需求,那么最好在编译PHP的时候添加--with-shmo ...
- <转>UNIX 共享内存应用中的问题及解决方法
http://www.ibm.com/developerworks/cn/aix/library/au-cn-sharemem/ 共享内存是一种非常重要且常用的进程间通信方式,相对于其它IPC机制,因 ...
- Linux进程IPC浅析[进程间通信SystemV共享内存]
Linux进程IPC浅析[进程间通信SystemV共享内存] 共享内存概念,概述 共享内存的相关函数 共享内存概念,概述: 共享内存区域是被多个进程共享的一部分物理内存 多个进程都可把该共享内存映射到 ...
- 阐述linux IPC(五岁以下儿童):system V共享内存
[版权声明:尊重原创.转载请保留源:blog.csdn.net/shallnet 要么 .../gentleliu,文章学习交流,不用于商业用途] system V共享内存和posix ...
- 五十、进程间通信——System V IPC 之共享内存
50.1 共享内存 50.1.1 共享内存的概念 共享内存区域是被多个进程共享的一部分物理内存 多个进程都可把该共享内存映射到自己的虚拟内存空间.所有用户空间的进程若要操作共享内存,都要将其映射到自己 ...
- IPC 进程间通信方式——共享内存
共享内存 共享内存区域是被多个进程共享的一部分物理内存. 多个进程都可以把共享内存映射到自己的虚拟空间.所有用户空间的进程要操作共享内存,都要将其映射到自己的虚拟空间,通过映射的虚拟内存空间地址去操作 ...
随机推荐
- Python 全栈开发七 面向对象
一.编程范式 编程是程序员用特定的语法+数据结构+算法组成的代码来告诉计算机如何执行任务的过程 , 一个程序是程序员为了得到一个任务结果而编写的一组指令的集合,正所谓条条大路通罗马,实现一个任务的方式 ...
- 前端MD5加密【单向加密】
密码存储的方式: 密码该如何存储呢?按照安全性由低到高,有这样几种选择: 1.密码名文直接存储在系统中 2.密码经过对称加密后再存储 3.密码经过非对称加密后再存储 步骤: 1.用户端:用户提交用户名 ...
- linux 释放内存及查看内存命令
查看内存使用情况: free -m 清理内存: echo 1 > /proc/sys/vm/drop_caches 再次查看内存使用情况 free -m 查看内存条数命令: dmidecode ...
- iOS 新浪微博-5.2 首页微博列表_转发微博/工具栏
继续于上一篇,还是做首页的功能,这一篇把剩下的首页继续完善. 看看上面的图片,分析: 1.转发微博里面的内容,和原创微博是一样的,由文字+配图组成.这应该放在一个UIView里处理. 2.工具栏也当成 ...
- cocos2d-x JS 获取屏幕大小或中点
以一张背景图为例: var HelloWorldLayer = cc.Layer.extend({ ctor:function () { this._super(); var bg = new cc. ...
- linux 小笔记
//强杀pid2306的进程 kill -9 2306 //查看80端口占用情况 lsof -i :80 //杀死mysql的所有进程 sudo killall mysqld //关闭占用80端口的所 ...
- C# Control.Invoke匿名委托
if (txbValue.InvokeRequired) txbValue.Invoke(new MethodInvoker(delegate() { ...
- hessian 在spring中的使用 (bean 如 Dao无法注入的问题)
hessian的主要结构分客户端与服务端,中间基于http传输.客户端主要做的事情是把对远程接口调用序列化为流,并传输到服务端:服务端主要做的事情是把传输过来的流反序列化为对服务的请求,调用相应服务后 ...
- 混合型log,info按大小分,error按日期
1.配置文件 <?xml version="1.0" encoding="utf-8"?> <configuration> <!- ...
- d'jang基础
1,建立一个名为guest的django项目,django-admin startproject guest 生成一个guest文件夹,包含一个guest文件夹和一个manage.py cd gue ...