首頁  >  文章  >  後端開發  >  實例詳解php是如何創建共享記憶體減少負載的

實例詳解php是如何創建共享記憶體減少負載的

藏色散人
藏色散人轉載
2022-11-03 17:03:033870瀏覽

本文要跟大家介紹在PHP中如何建立共享記憶體減少負載,這裡大家要了解一個函數shmop,以下就跟著文章講解來學習吧~

PHP做記憶體共享有兩套介面。一個是shm,它其實是變數共享,會把物件變數序列化後再儲存。使用起來倒是挺方便,但是序列化儲存對於效率優先的記憶體存取操作而言就沒啥意義了。另外一個是shmop,它是Linux和Windows通用的,不過功能上比shm弱了一些,在Linux 上,這些函數直接是透過呼叫shm* 系列的函數實現,而Winodows 上也透過對系統函數的封裝實現了同樣的調用。

要建立共享記憶體段需要使用函數shmop,那麼前提需要開啟擴充。 【推薦學習:PHP影片教學

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”,它允許您存取只讀記憶體段,只讀存取模式“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来判断你读取的是哪一块内存。 owner:创建该共享内存块的用户 bytes:该内存块的大小 status:当前状态,如:dest,即将删除等。

项目实际应用小案例

/**
 * 将领技能
 */
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 (
=> 
 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;,
 ),
=> 
 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中文網其他相關文章!

陳述:
本文轉載於:jb51.net。如有侵權,請聯絡admin@php.cn刪除