php使用shmop函数创建共享内存减少负载的方法
PHP做内存共享有两套接口。一个是shm,它实际上是变量共享,会把对象变量序列化后再储存。使用起来倒是挺方便,但是序列化存储对于效率优先的内存访问操作而言就没啥意义了。另外一个是shmop,它是Linux和Windows通用的,不过功能上比shm弱了一些,在Linux上,这些函数直接是通过调用shm*系列的函数实现,而Winodows上也通过对系统函数的封装实现了同样的调用。
要创建共享内存段需要使用函数shmop,那么前提需要开启扩展。
shmop主要函数
shmop_open(创建或打开共享内存块)、shmop_write(向共享内存块中写入数据)、shmop_read(从共享内存块中读取数据)、shmop_size(获取共享内存块的大小)、shmop_close(关闭共享内存块)、shmop_delete(删除共享内存块)
shmop_open(创建内存段)
该函数中出现的第一个事物是系统ID参数。这是标识系统中的共享内存段的数字。第二个参数是访问模式,它非常类似于fopen函数的访问模式。您可以在4种不同的模式下访问一个内存段:
模式“a”,它允许您访问只读内存段,只读访问模式“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 ------SharedMemorySegments-------- keyshmidownerpermsbytesnattchstatus 0x000000000gdm6003932162dest 0x0000000032769gdm6003932162dest 0x4337b101884750nobody64410240命令说明
key:共享内存的唯一的key值,共享内存通过该key来判断你读取的是哪一块内存。owner:创建该共享内存块的用户bytes:该内存块的大小status:当前状态,如:dest,即将删除等。
项目实际应用小案例
/** *将领技能 */ classGeneralskill_modelextendsCI_Model{ private$_memory_key=0x4337b001;//共享内存地址key private$_memory_size=1048576;//开辟共享内存大小//最好根据实际数据长度大小定义。 publicfunction__construct(){ parent::__construct(); } publicfunctionget_skill_list(){ $data=[]; $shmid=@shmop_open($this->_memory_key,'a',0644,$this->_memory_size); if($shmid===FALSE){ $shmid=@shmop_open($this->_memory_key,'c',0644,$this->_memory_size); $data=$this->return_skill_list(); shmop_write($shmid,json_encode($data),0); @shmop_close($shmid); return$data; } $data=json_decode(preg_replace('/[\x00-\x1F\x80-\x9F]/u','',trim(shmop_read($shmid,0,$this->_memory_size))),true); @shmop_close($shmid); return$data; } publicfunctionreturn_skill_list(){//这里是一个超大的数组,其实就是把这个数组json化,然后存入共享内存段。其实可以用redis等其他缓存...这里我就是为了不用redis等其他nosql才用的shmop returnarray( => array('id'=>'1','animation'=>'13','skill_type'=>'1','power_type'=>'1','site'=>'1','type'=>'1','paramete'=>'0','paramete2'=>'0','paramete3'=>'0','chance'=>'0','ratio'=>'1', ), => array('id'=>'2','animation'=>'3','skill_type'=>'2','power_type'=>'1','site'=>'1','type'=>'1','paramete'=>'0','paramete2'=>'0','paramete3'=>'0','chance'=>'0','ratio'=>'2', ),..........................................当然你要考虑的是,如果数据更新的话,那么内存段也要删除,并且更新数据…通过shmop_delete可以删除。这就需要你们自己根据项目应用来考虑了
还有就是这篇文章只是为了简单的读,并没有出现复杂的读写,否则可能会出现进程互斥等意想不到的冲突如果复杂,那么就可以考虑信号量了
到此这篇关于php使用shmop函数创建共享内存减少负载的文章就介绍到这了,更多相关php创建共享内存减少负载内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!