ホームページ  >  記事  >  バックエンド開発  >  PHP は単純に shmop 関数を使用して共有メモリを作成し、サーバーの負荷を軽減します。

PHP は単純に shmop 関数を使用して共有メモリを作成し、サーバーの負荷を軽減します。

不言
不言オリジナル
2018-07-06 15:57:193133ブラウズ

この記事では、サーバーの負荷を軽減するために、PHP が shmop 関数を使用して共有メモリを作成する方法を主に紹介します。これには、特定の参考値があります。ここで共有します。必要な友人はそれを参照してください。

前回の記事 このブログ【共有メモリの概念とメリット・デメリットを理解する】で共有メモリの概念について説明しました。単純に共有メモリを使用してみましょう (実際には、redis などの他のツールを使用することもできます)

PHP にはメモリ共有用の 2 セットのインターフェイスがあります。 1 つは shm で、実際には変数共有であり、オブジェクト変数を格納する前にシリアル化します。使用すると非常に便利ですが、効率を優先するメモリアクセス操作ではシリアル化されたストレージは意味がありません。もう 1 つは shmop で、Linux と Windows に共通ですが、shm よりも機能が弱く、Linux では shm* 系の関数を呼び出すことで直接実装されますが、Windows ではシステムをカプセル化することで実装されます。関数が同じ呼び出しを行いました。ここで最初に使用するのはシュモップです。

##共有メモリ セグメントを作成するには、関数 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パラメータです。これは、システム内の共有メモリセグメントを識別する番号です。 2 番目のパラメータはアクセス モードで、fopen 関数のアクセス モードとよく似ています。メモリ セグメントには 4 つの異なるモードでアクセスできます。

モード "a" では、読み取り専用メモリ セグメントにアクセスできます。

モード "w" では、読み取り専用メモリ セグメントにアクセスできます。読み取り専用メモリ セグメント 読み取りと書き込みのためのメモリ セグメント、読み取りと書き込み

モード "c"、新しいメモリ セグメントを作成します。メモリ セグメントがすでに存在する場合は、読み取りと書き込みのためにそれを開こうとします
モード"n" の場合、新しいメモリを作成します。同じキーを持つセグメントがすでに存在する場合、作成は失敗します。これは、共有メモリを安全に使用するためです。
3 番目のパラメータはメモリ セグメントのアクセス許可です。ここには 8 進数値を指定する必要があります。

4 番目のパラメータは、メモリ セグメント サイズをバイト単位で指定します。使用される共有メモリセグメントは固定長であるため、保存時および読み取り時にデータの長さを計算する必要があり、そうでないと書き込みに失敗したり、NULL 値が読み取られる可能性があります。 。

この関数は、他の関数がこの共有メモリ セグメントを操作するために使用できる ID 番号を返すことに注意してください。この ID は、パラメータとして渡されるシステム ID とは異なり、共有メモリのアクセス ID です。この 2 つを混同しないように注意してください。失敗すると、shmop_open は FALSE を返します。メモリ ブロックを作成するときは、キー パラメータに変数ではなく定数を使用することをお勧めします。そうしないと、メモリ リークが発生する可能性があります。

shmop_write (メモリ セグメントへのデータの書き込み)

この関数は fwrite 関数に似ており、次の 2 つのパラメータがあります: オープン ストリーム リソース (fopen によって返される)そして書き込みたいデータ。 shmop_write 関数もこのタスクを実行します。

最初のパラメータは shmop_open によって返される ID で、操作している共有メモリ ブロックを識別します。 2 番目のパラメータは保存したいデータで、最後の 3 番目のパラメータは書き込みを開始する位置です。デフォルトでは、書き込みを開始する場所を示すために常に 0 を使用します。この関数は失敗すると FALSE を返し、成功すると書き込まれたバイト数を返すことに注意してください。

shmop_read(メモリ セグメントからのデータの読み取り)

共有メモリ セグメントからのデータの読み取りは非常に簡単です。必要なのは、開いているメモリ セグメントと shmop_read 関数だけです。この関数はいくつかのパラメータを受け取り、fread のように動作します。

ここのパラメータに注意してください。 shmop_read 関数は shmop_open によって返される ID を受け入れますが、これはすでにわかっていますが、他の 2 つのパラメーターも受け入れます。 2 番目の引数は、読み取りたいメモリ セグメント内の位置で、3 番目の引数は読み取りたいバイト数です。 2 番目のパラメータは常にデータの始まりを示す 0 にすることができますが、3 番目のパラメータは読み込むバイト数がわからないため、問題が発生する可能性があります。

これは fread 関数で行うことと非常に似ており、オープン ストリーム リソース (fopen によって返される) とストリームから読み込むバイト数という 2 つのパラメーターを受け取ります。ファイルを完全に読み取るには、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 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。