PHP共享内存使用与信号控制实例分析


Posted in PHP onMay 09, 2018

本文实例讲述了PHP共享内存使用与信号控制。分享给大家供大家参考,具体如下:

共享内存

共享内存的使用主要是为了能够在同一台机器不同的进程中共享一些数据,比如在多个 php-fpm 进程中共享当前进程的使用情况。这种通信也称为进程间通信(Inter-Process Communication),简称 IPC。

PHP 内置的 shmop 扩展 (Shared Memory Operations) 提供了一系列共享内存操作的函数(可能是用的人不多吧,这一块儿的文档还没有中文翻译)。在 Linux 上,这些函数直接是通过调用 shm* 系列的函数实现,而 Winodows 上也通过对系统函数的封装实现了同样的调用。

主要函数:

shmop_close — 关闭共享内存块

shmop_delete — 删除共享内存块

shmop_open — 创建或打开共享内存块

shmop_read — 从共享内存块中读取数据

shmop_size — 获取共享内存块的大小

shmop_write — 向共享内存块中写入数据

与此相关的还有一个很重要的函数:ftok,通过文件的 inode 信息(*nix 上通过 stat 或 ls -i 命令查看)创建 IPC 的唯一 key(文件/文件夹的 inode 是唯一的)。这个函数在 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 的第二个参数是个 flag,类似 fopen 的第二个参数,其取值有以前几个:

"a" 只读访问;

"c" 如果内存片段不存在,则创建,如果存在,则可读写;

"w" 读写;

"n" 创建新的内存片段,如果同样 key 的已存在,则会创建失败,这是为了安全使用共享内存考虑。

此外,由于使用的共享内存片段是固定长度的,在存储和读取的时候要计算好数据的长度,不然可能会写入失败或者读取空值。

信号控制

既然上面使用到了共享内存存储数据,就需要考虑是否有多个进程同时写入数据到共享内存的情况,是否需要避免冲突。如果是这样,就需要引入信号量进行控制。

PHP 也提供了类似的内置扩展 sysvsem(这个扩展在 Windows 环境下没有,文档中将 ftok 函数也归到这个扩展中,但实际上ftok 是在标准函数库中提供的,所以在 Windows 下也是可用的)。

在说信号量控制之前,先说另外一件有意思的事情:看官方文档你会发现这里同样也有共享内存操作的函数(shm_*),因为这其实是同一类别(或者说来自于同一作者)的三个扩展,还有一个是 sysvmsg(队列消息) 。函数的实现上稍有差别,但实际做的事情基本相同。这和上文的 shmop 扩展有什么区别呢?shmop 源码下的 README 文件有简单的说明:

PHP already had a shared memory extension (sysvshm) written by Christian Cartus <cartus@atrior.de>, unfortunately this extension was designed with PHP only in mind and offers high level features which are extremely bothersome for basic SHM we had in mind.

简单说来: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 相关文章推荐
Zend Studio (eclipse)使用速度优化方法
Mar 23 PHP
sphinx增量索引的一个问题
Jun 14 PHP
php 团购折扣计算公式
Nov 24 PHP
PHP 安全检测代码片段(分享)
Jul 05 PHP
请离开include_once和require_once
Jul 18 PHP
PHP 提取图片img标记中的任意属性的简单实例
Dec 10 PHP
php中自定义函数dump查看数组信息类似var_dump
Jan 27 PHP
php使用fopen创建utf8编码文件的方法
Oct 31 PHP
php中count获取多维数组长度的方法
Nov 03 PHP
php实现留言板功能(代码详解)
Mar 28 PHP
PHP实现微信模拟登陆并给用户发送消息的方法【文字,图片,图文】
Jun 29 PHP
Docker 安装 PHP并与Nginx的部署实例讲解
Feb 27 PHP
php curl批处理实现可控并发异步操作示例
May 09 #PHP
php使用curl伪造来源ip和refer的方法示例
May 08 #PHP
PHP+ajax实现获取新闻数据简单示例
May 08 #PHP
PHP 计算两个特别大的整数实例代码
May 07 #PHP
详解PHP发送邮件知识点
May 06 #PHP
PHP学习笔记之session
May 06 #PHP
PHP中cookie知识点学习
May 06 #PHP
You might like
UTF8编码内的繁简转换的PHP类
2009/07/09 PHP
深入了解 register_globals (附register_globals=off 网站打不开的解决方法)
2012/06/27 PHP
php ci框架验证码实例分析
2013/06/26 PHP
PHP图片添加水印功能示例小结
2016/10/03 PHP
Kindeditor编辑器添加图片上传水印功能(php代码)
2017/08/03 PHP
模仿JQuery.extend函数扩展自己对象的js代码
2009/12/09 Javascript
javascript iframe编程相关代码
2009/12/28 Javascript
Jquery动态改变图片IMG的src地址示例
2013/06/25 Javascript
node.js使用nodemailer发送邮件实例
2014/03/10 Javascript
JavaScript 学习笔记之变量及其作用域
2015/01/14 Javascript
gameboy网页闯关游戏(riddle webgame)--仿微信聊天的前端页面设计和难点
2016/02/21 Javascript
jQuery编写网页版2048小游戏
2017/01/06 Javascript
原生js实现图片放大缩小计时器效果
2017/01/20 Javascript
jQuery实现图片滑动效果
2017/03/08 Javascript
微信小程序 自动登陆PHP源码实例(源码下载)
2017/05/08 Javascript
[06:07]刀塔密之二:攻之吾命受之吾幸
2014/07/03 DOTA
python实现simhash算法实例
2014/04/25 Python
教你如何在Django 1.6中正确使用 Signal
2014/06/22 Python
python迭代器与生成器详解
2016/03/10 Python
Python环境下搭建属于自己的pip源的教程
2016/05/05 Python
windows下python之mysqldb模块安装方法
2017/09/07 Python
python分治法求二维数组局部峰值方法
2018/04/03 Python
python3实现字符串的全排列的方法(无重复字符)
2018/07/07 Python
在python中利用numpy求解多项式以及多项式拟合的方法
2019/07/03 Python
python logging通过json文件配置的步骤
2020/04/27 Python
学习python需要有编程基础吗
2020/06/02 Python
基于Python爬取fofa网页端数据过程解析
2020/07/13 Python
全球领先的各类汽车配件零售商:Advance Auto Parts
2016/08/26 全球购物
一套SQL笔试题
2016/08/14 面试题
营销总经理岗位职责
2014/02/02 职场文书
入党自我鉴定
2014/03/25 职场文书
大型公益活动策划方案
2014/08/20 职场文书
检讨书格式
2015/05/07 职场文书
mysql备份策略的实现(全量备份+增量备份)
2021/07/07 MySQL
十大最强电系宝可梦,阿尔宙斯电系之一,第七被称为雷神
2022/03/18 日漫
浅谈Redis变慢的原因及排查方法
2022/06/21 Redis