首頁  >  文章  >  後端開發  >  php簡單使用shmop函數建立共享記憶體減少伺服器負載

php簡單使用shmop函數建立共享記憶體減少伺服器負載

不言
不言原創
2018-07-06 15:57:193147瀏覽

這篇文章主要介紹了關於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, &#39;c&#39;, 0644, 1024);
//读取并写入数据
$data = shmop_read($shm_id, 0, 1024);
shmop_write($shm_id, json_encode($data), 0);
$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 0              gdm              600                 393216            2         dest         
0x00000000 32769             gdm              600                 393216            2         dest                              
0x4337b101 884750           nobody         644                 1024                0

命令说明

key :共享内存的唯一的key值,共享内存通过该key来判断你读取的是哪一块内存。
shmid:当使用key来获取内存时,你获得的是这个id的值。它作为你操作内存块的标识。
owner:创建该共享内存块的用户
perms:该共享内存的读写权限,8禁止,可以是777,与文件的读写权限一致。
bytes:该内存块的大小
nattch:连接该内存块的进程数
status:当前状态,如:dest,即将删除等。

项目实际应用小案例

<?php
/**
 * 将领技能
 */
class Generalskill_model extends CI_Model {
  
  private $_memory_key = 0x4337b001;   //共享内存地址key
  private $_memory_size = 1048576;     //开辟共享内存大小  //最好根据实际数据长度大小定义。

  public function __construct() {
    parent::__construct();
  }

  public function get_skill_list() {
    $data = [];
    $shmid = @shmop_open($this->_memory_key, &#39;a&#39;, 0644, $this->_memory_size);  

    if ($shmid === FALSE) {
        $shmid = @shmop_open($this->_memory_key, &#39;c&#39;, 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(&#39;/[\x00-\x1F\x80-\x9F]/u&#39;, &#39;&#39;, trim(shmop_read($shmid, 0, $this->_memory_size))), true);
    @shmop_close($shmid);
    return $data;    
  
  }

  public function return_skill_list() {   //这里是一个超大的数组,其实就是把这个数组json化,然后存入共享内存段。  其实可以用redis等其他缓存...这里我就是为了不用redis等其他nosql才用的shmop
    return array (
  1 => 
  array (&#39;id&#39; => &#39;1&#39;,&#39;animation&#39; => &#39;13&#39;,&#39;skill_type&#39; => &#39;1&#39;,&#39;power_type&#39; => &#39;1&#39;,&#39;site&#39; => &#39;1&#39;,&#39;type&#39; => &#39;1&#39;,&#39;paramete&#39; => &#39;0&#39;,&#39;paramete2&#39; => &#39;0&#39;,&#39;paramete3&#39; => &#39;0&#39;,&#39;chance&#39; => &#39;0&#39;,&#39;ratio&#39; => &#39;1&#39;,
  ),
  2 => 
  array (&#39;id&#39; => &#39;2&#39;,&#39;animation&#39; => &#39;3&#39;,&#39;skill_type&#39; => &#39;2&#39;,&#39;power_type&#39; => &#39;1&#39;,&#39;site&#39; => &#39;1&#39;,&#39;type&#39; => &#39;1&#39;,&#39;paramete&#39; => &#39;0&#39;,&#39;paramete2&#39; => &#39;0&#39;,&#39;paramete3&#39; => &#39;0&#39;,&#39;chance&#39; => &#39;0&#39;,&#39;ratio&#39; => &#39;2&#39;,
  ),..........................................

当然你要考虑的是,如果数据更新的话,那么内存段也要删除,并且更新数据......................通过shmop_delete可以删除 。这就需要你们自己根据项目应用来考虑了

还有就是我这里只是为了简单的读,并没有出现复杂的读写,否则可能会出现进程互斥等意想不到的冲突~如果复杂,那么就可以考虑信号量了~

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

php操作共享内存shmop类及简单使用测试的代码

php实现共享内存进程通信函数(_shm)

以上是php簡單使用shmop函數建立共享記憶體減少伺服器負載的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn