今回は、PHP の共有メモリ使用量とシグナル制御のユースケース分析をお届けします。PHP 共有メモリ使用量とシグナル制御の使用法に関する 注意事項 について、実際のケースを見てみましょう。
共有メモリ
共有メモリの使用は主に、複数の php-fpm プロセスで現在のプロセスの使用状況を共有するなど、同じマシン上の異なるプロセスで一部のデータを共有できるようにすることです。この種の通信は、プロセス間通信 (略して IPC) とも呼ばれます。
PHP の組み込み shmop 拡張機能 (Shared Memory Operations) は、共有メモリ操作のための一連の関数を提供します (おそらく、これを使用する人が少ないため、このドキュメントはまだ中国語に翻訳されていません)。 Linux では、これらの関数は shm* 一連の関数を呼び出すことによって直接実装されますが、Windows では、同じ呼び出しがシステム関数をカプセル化することによっても実装されます。
主な関数:
shmop_close — 共有メモリブロックを閉じる
shmop_delete — 削除共有メモリブロック
shmop_open — 共有メモリブロックを作成または開く
shmop_read — 共有メモリからブロック内のデータを読み取ります
shmop_size — 共有メモリ ブロックのサイズを取得します
shmop_write — 共有メモリ ブロックにデータを書き込みます
これに関連する非常に重要な関数もあります: ファイルを介した ftok i ノード情報 (*nix の stat または ls -i コマンドで表示) により、IPC 用の一意のキーが作成されます (ファイル/フォルダーの i ノードは一意です)。この関数は、同じ名前のシステム関数を直接呼び出すことによって Linux でも実装されますが、Windows では依然として一部のカプセル化が使用されています。
簡単なカウントの例:
<?php # 创建一块共享内存 $shm_key = ftok(FILE, 't'); $shm_id = shmop_open($shm_key, 'c', 0644, 8); # 读取并写入数据 $count = (int) shmop_read($shm_id, 0, 8) + 1; shmop_write($shm_id, str_pad($count, 8, '0', STR_PAD_LEFT), 0); // echo shmop_read($shm_id, 0, 8); # 关闭内存块,并不会删除共享内存,只是清除 PHP 的资源 shmop_close($shm_id);
上記のコードはカウントを 1 つ増やすことを実行せず、データは異なるプロセス間で共有されます。つまり、このメモリを手動で削除しない限り、このデータはリセットされません。
少し注意が必要な点があります。shmop_open の 2 番目のパラメータは fopen の 2 番目のパラメータと同様にフラグであり、その値は次のとおりです。
"a" 読み取り専用アクセス。
"c" if メモリセグメントが存在しない場合は、メモリセグメントを作成します。存在する場合は、読み取りと書き込みが可能です。"n" は、新しいメモリセグメントを作成します。キーがすでに存在する場合、作成は失敗します。これは、共有メモリの安全な使用を考慮するためです。 また、使用される共有メモリセグメントは固定長であるため、保存時と読み込み時にデータの長さを計算する必要があり、そうしないと書き込みに失敗したり、null値が読み込まれる可能性があります。 信号制御上記のデータの保存には共有メモリが使用されるため、複数のプロセスが同時に共有メモリにデータを書き込んでいるかどうか、競合を回避する必要があるかどうかを考慮する必要があります。その場合は、制御用のセマフォを導入する必要があります。
PHP も同様の組み込み拡張機能 sysvsem を提供しています (この拡張機能は Windows 環境では使用できません。ドキュメントでは ftok 関数もこの拡張機能に含まれていますが、実際には ftok は標準関数ライブラリで提供されているため、 Windows でも使用可能です)。 セマフォ制御について話す前に、別の興味深いことについて話させてください。公式ドキュメントを見ると、共有メモリ操作 (shm_*) 用の関数もあることがわかります。これは、これらは実際には同じカテゴリ (または、同じ作成者) )、そして 1 つは sysvmsg (queue
message) です。関数の実装は若干異なりますが、実際に行うことは基本的に同じです。これと上記の shmop 拡張機能の違いは何ですか? shmop ソース コードの下の README ファイルには簡単な説明があります:PHP には、Christian Cartus
简单说来:sysvshm 扩展提供的方法并不是原封不动的存储用户的数据,而是先使用 PHP 的变量序列化函数对参数进行序列化然后再进行存储。这就导致通过这些方法存储的数据无法和非 PHP 进程共享。不过这样也能存储更丰富的 PHP 数据类型,上文的扩展中 shmop_write 只能写入字符串。那么为什么 sysvshm 同样不支持 Windows 呢?因为其并没有引入封装了 shm* 系列函数的tsrm_win32.h 的头文件。
引入信号控制之后的示例:
<?php $id_key = ftok(FILE, 't'); $sem_id = sem_get($id_key); # 请求信号控制权 if (sem_acquire($sem_id)) { $shm_id = shmop_open($id_key, 'c', 0644, 8); # 读取并写入数据 $count = (int) shmop_read($shm_id, 0, 8) + 1; shmop_write($shm_id, str_pad($count, 8, '0', STR_PAD_LEFT), 0); // echo shmop_read($shm_id, 0, 8); # 关闭内存块 shmop_close($shm_id); # 释放信号 sem_release($sem_id); }
但是本地想模拟实现写入冲突实际上是非常难的(考虑到计算机的执行速度)。在本地测试中,使用 for 循环操作时如果不使用shmop_close 关闭资源会出现无法打开共享内存的错误警告。这应该是因为正在共享内存被上一次操作占用中还没有释放导致。
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
以上がPHP 共有メモリの使用量と信号制御のユースケース分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。