共享內存是一種在相同機器中的應用程序之間交換數據的有效方式。一個進程可建立一個可供其餘進程訪問的內存段,只要它分配了正確的權限。每一個內存段擁有一個唯一的 ID(稱爲 shmid),這個 ID 指向一個物理內存區域,其餘進程可在該區域操做它。建立並提供了合適的權限以後,同一臺機器中的其餘進程就能夠操做這些內存段:讀取、寫入和刪除。 php
這代表使用 C 語言編寫的應用程序可與使用其餘語言(好比 Java™ 或 PHP)編寫的應用程序共享信息。它們均可以共享信息,只要它們可訪問和理解該信息。共享內存在針對大部分語言的實現中獲得了普遍使用,因此訪問應該不是 問題。要理解信息,咱們可使用一種標準格式,好比 XML 或 JSON。 git
共享內存的使用是一種在進程之間交換數據的快速方法,主要由於在建立內存段以後傳遞數據,不會涉及內核。這種方法經常稱爲進程間通訊 (IPC)。其餘 IPC 方法包括管道、消息隊列、RPC 和套接字。當使用須要彼此通訊的應用程序的生態系統時,這種在應用程序之間快速、可靠地交換數據的能力很是有用。取決於生態系統的大小,使用數據庫在應用 程序之間交換信息的經常使用方法經常會致使查詢緩慢,甚至 I/O 阻塞。使用共享內存,沒有 I/O 會減緩開發人員的進度。 github
本文的提議很是簡單,學習如何使用 PHP 建立和操做共享內存段,使用它們存儲可供其餘應用程序使用的數據集。即便沒有使用共享內存交換數據的計劃,它自己也在許多好處,由於它使應用程序可以遠離 I/O 問題。將數據集直接存儲在內存中具備諸多優點,從 Web 服務數據緩存到會話共享。它是一個很是有用的概念,每一個 PHP 開發人員都應該知道。 數據庫
共享內存和 PHP json
PHP 擁有豐富的可用擴展,共享內存也同樣。使用一些共享的函數,無需安裝任何擴展,開發人員就可以輕鬆操做內存段。 數組
建立內存段 緩存
共享內存函數相似於文件操做函數,但無需處理一個流,您將處理一個共享內存訪問 ID。第一個示例就是shmop_open函數,它容許您打開一個現有的內存段或建立一個新內存段。此函數很是相似於經典的fopen函數,後者打開用於文件操做的流,返回一個資源供其餘但願讀取或寫入該打開的流的函數使用。讓咱們看看清單 1 中的shmop_open。 函數
<?php $systemid = 864; // System ID for the shared memory segment $mode = "c"; // Access mode $permissions = 0755; // Permissions for the shared memory segment $size = 1024; // Size, in bytes, of the segment $shmid = shmop_open($systemid, $mode, $permissions, $size); ?> |
該函數中出現的第一個事物是系統 ID 參數。這是標識系統中的共享內存段的數字。第二個參數是訪問模式,它很是相似於fopen函數的訪問模式。您能夠在 4 種不一樣的模式下訪問一個內存段: 工具
第三個參數是內存段的權限。您必須在這裏提供一個八進制值。 post
第四個參數提供內存段大小,以字節爲單位。在寫入一個內存段以前,您必須在它之上分配適當的字節數。
請注意,此函數返回一個 ID 編號,其餘函數可以使用該 ID 編號操做該共享內存段。這個 ID 是共享內存訪問 ID,與系統 ID 不一樣,它以參數的形式傳遞。請注意不要混淆這二者。若是失敗,shmop_open將返回 FALSE。
向內存段寫入數據
使用shmop_write函數向共享內存塊寫入數據。此函數的使用很簡單,它僅接受 3 個參數,如清單 2 所示。
<?php $shmid = shmop_open(864, 'c', 0755, 1024); shmop_write($shmid, "Hello World!", 0); ?> |
這個函數相似於fwrite函數,後者有兩個參數:打開的流資源(由fopen返回)和您但願寫入的數據。shmop_write函數也執行此任務。
第一個參數是shmop_open返回的 ID,它識別您操做的共享內存塊。第二個參數是您但願存儲的數據,最後的第三個參數是您但願開始寫入的位置。默認狀況下,咱們始終使用 0 來表示開始寫入的位置。請注意,此函數在失敗時會返回 FALSE,在成功時會返回寫入的字節數。
從內存段讀取數據
從共享內存段讀取數據很簡單。您只須要一個打開的內存段和shmop_read函數。此函數接受一些參數,工做原理相似於fread。參見清單 3,讀取一個 PHP 文件的內容。
<?php $stream = fopen('file.txt', 'r+'); fwrite($stream, "Hello World!"); echo fread($stream, 11); ?> |
讀取共享內存段的內容的過程與此相似,如清單 4 所示:
<?php $shmid = shmop_open(864, 'c', 0755, 1024); shmop_write($shmid, "Hello World!", 0); echo shmop_read($shmid, 0, 11); ?> |
請留意這裏的參數。shmop_read函數將接受shmop_open返回的 ID,咱們已知道它,不過它還接受另外兩個參數。第二個參數是您但願從內存段讀取的位置,而第三個是您但願讀取的字節數。第二個參數能夠始終爲 0,表示數據的開頭,但第三個參數可能存在問題,由於咱們不知道咱們但願讀取多少字節。
這很是相似於咱們在fread函數中的行爲,該函數接受兩個參數:打開的流資源(由fopen返回)和您但願從該流讀取的字節數。使用filesize函數(它返回一個文件中的字節數)來完整地讀取它。
幸運的是,當使用共享內存段時,shmop_size函數返回一個內存段的大小(以字節爲單位),相似於filesize函數。參見清單 5。
<?php $shmid = shmop_open(864, 'c', 0755, 1024); shmop_write($shmid, "Hello World!", 0); $size = shmop_size($shmid); echo shmop_read($shmid, 0, $size); ?> |
刪除內存段
咱們學習瞭如何打開、寫入和讀取共享內存段。要完成咱們的 CRUD 類,咱們還須要學習如何刪除內存段。該任務可以使用shmop_delete函數輕鬆完成,該函數僅接受一個參數:咱們但願刪除的共享內存 ID。
<?php $shmid = shmop_open(864, 'c', 0755, 1024); shmop_write($shmid, "Hello World!", 0); shmop_delete($shmid); ?> |
這不會實際刪除該內存段。它將該內存段標記爲刪除,由於共享內存段在有其餘進程正在使用它時沒法被刪除。shmop_delete函數將該內存段標記爲刪除,阻止任何其餘進程打開它。要刪除它,咱們須要關閉該內存段。
關閉內存段
打開一個共享內存段會 「附加」 到它。附加該內存段以後,咱們可在其中進行讀取和寫入,但完成操做後,咱們必須從它解除。這使用清單 7 中的shmop_close函數來完成。
這很是相似於處理文件時的fclose函數。打開包含一個文件的流並在其中讀取或寫入數據後,咱們必須關閉它,不然將發生鎖定。
<?php $shmid = shmop_open(864, 'c', 0755, 1024); shmop_write($shmid, "Hello World!", 0); shmop_delete($shmid); shmop_close($shmid); ?>
使用共享內存做爲一個存儲選項
有了共享內存和共享內存段上基本 CRUD 操做的基本知識,是時候應用此知識了。咱們可使用共享內存做爲一種獨特的存儲選項,提供快速讀/寫操做和進程互操做性等優點。對於 Web 應用程序,這意味着:
在繼續以前,我想介紹一個名爲 SimpleSHM 小型庫。SimpleSHM 是一個較小的抽象層,用於使用 PHP 操做共享內存,支持以一種面向對象的方式輕鬆操做內存段。在編寫使用共享內存進行存儲的小型應用程序時,這個庫可幫助建立很是簡潔的代碼。要了解 SimpleSHM,請訪問 GitHub 頁面。
您可使用 3 個方法進行處理:讀、寫和刪除。從該類中簡單地實例化一個對象,能夠控制打開的共享內存段。清單 8 展現了基本用途。
<?php $memory = new SimpleSHM; $memory->write('Sample'); echo $memory->read(); ?> |
請注意,這裏沒有爲該類傳遞一個 ID。若是沒有傳遞 ID,它將隨機選擇一個編號並打開該編號的新內存段。咱們能夠以參數的形式傳遞一個編號,供構造函數打開現有的內存段,或者建立一個具備特定 ID 的內存段,如清單 9 所示。
<?php $new = new SimpleSHM(897); $new->write('Sample'); echo $new->read(); ?> |
神奇的方法__destructor負責在該內存段上調用shmop_close來取消設置對象,以與該內存段分離。咱們將這稱爲 「SimpleSHM 101」。如今讓咱們將此方法用於更高級的用途:使用共享內存做爲存儲。存儲數據集須要序列化,由於數組或對象沒法存儲在內存中。儘管這裏使用了 JSON 來序列化,但任何其餘方法(好比 XML 或內置的 PHP 序列化功能)也已足夠。清單 10 給出了一個示例。
<?php require('SimpleSHM.class.php'); $results = array( 'user' => 'John', 'password' => '123456', 'posts' => array('My name is John', 'My name is not John') ); $data = json_encode($results); $memory = new SimpleSHM; $memory->write($data); $storedarray = json_decode($memory->read()); print_r($storedarray); ?> |
咱們成功地將一個數組序列化爲一個 JSON 字符串,將它存儲在共享內存塊中,從中讀取數據,去序列化 JSON 字符串,並顯示存儲的數組。這看起來很簡單,但請想象一下這個代碼片斷帶來的可能性。您可使用它存儲 Web 服務請求、數據庫查詢或者甚至模板引擎緩存的結果。在內存中讀取和寫入將帶來比在磁盤中讀取和寫入更高的性能。
使用此存儲技術不只對緩存有用,也對應用程序之間的數據交換也有用,只要數據以兩端均可讀的格式存儲。不要低估共享內存在 Web 應用程序中的力量。可採用許多不一樣的方式來巧妙地實現這種存儲,唯一的限制是開發人員的創造力和技能。
結束語
本文介紹了用於操做共享內存段的 PHP 工具包中的大部分工具,解釋了共享內存的工做原理。此外,還提供了改進 Web 應用程序的建議,列出了在爲 Web 應用程序問題建立解決方案時要考慮的一些因素。這些概念和實現指南可幫助您創建一個起點。咱們構建的早期模型可幫助您構想更復雜的特性和解決方案。