本文要跟大家介紹在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, 'c', 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, '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; } public function return_skill_list() {<!-- --> //这里是一个超大的数组,其实就是把这个数组json化,然后存入共享内存段。 其实可以用redis等其他缓存...这里我就是为了不用redis等其他nosql才用的shmop return array ( => 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是如何創建共享記憶體減少負載的的詳細內容。更多資訊請關注PHP中文網其他相關文章!