关于PHP 共享内存的介绍、测试与 任务消息的使用示例

土豆条
土豆条 2015-12-14

关于PHP 共享内存的介绍与测试

概要说明

在开始之前,我们需要注意几点:
1.要了解内存的管理机制;
2.在要使用内存时要先申请;
3.在使用完毕后要及时释放资源;
4.要预防死锁;
5.在产生死锁时,应该有一个可靠,稳定的解决方案;

本函数库提供 System V 的信号处理机制。这个机制可以让系统限制同时使用行程所存取的资源。本函数库亦提供了内存共享的机制,可让不同的程序存取相同的变量,方便交换程序信息。
下表为系统的共享内存的限制值
SHMMAX 共享内存的最大值,一般为 131072 bytes
SHMMIN 共享内存的最小值,一般为 1 byte
SHMMNI 内存共享部分的最大值,一般为 100
SHMSEG 每个行程所能共享的最大内存空间,一般为 6

sem_get: 取得信号代码。
sem_acquire: 捕获信号。
sem_release: 释出信号。
shm_attach: 打开建立共享内存空间。
shm_detach: 中止共享内存空间链接。
shm_remove: 清除内存空间。
shm_put_var: 加入或更新内存空间中的变量。
shm_get_var: 取得内存空间中指定的变量。
shm_remove_var: 删除内存空间中指定的变量。

管理共享内存

server:/home/xisxy$ ipcs -sa


Semaphores:
T       ID     KEY        MODE       OWNER    GROUP  CREATOR   CGROUP NSEMS    OTIME    CTIME
s    65536    5432001 --rw------- _postgresql _postgresql _postgresql _postgresql    17 13:01:18 13:01:18
s    65537    5432002 --rw------- _postgresql _postgresql _postgresql _postgresql    17 13:01:18 13:01:18
s    65538    5432003 --rw------- _postgresql _postgresql _postgresql _postgresql    17  1:30:05 13:01:18
s   262147          0 --rw-rw-rw-    www    www    www    www     1 no-entry  0:00:52
s   262148          0 --rw-rw-rw-    www    www    www    www     1 no-entry  0:00:52
s   262149          0 --rw-rw-rw-    www    www    www    www     1 no-entry  0:00:52
s  1966086          0 --rw-rw-rw-    www    www    www    www     1 no-entry 19:18:32
s  1966087          0 --rw-rw-rw-    www    www    www    www     1 no-entry 19:18:32
s  1966088          0 --rw-rw-rw-    www    www    www    www     1 no-entry 19:18:32

server:/home/xisxy$ ipcrm -s 262147

也可以用如下方式,一次全部清理:

for i in `ipcs |grep www|awk  '{print $2}'`
do
ipcrm -m $i
ipcrm -s $i
done



共享内存查看清除命令ipcs和ipcrm

ipcs: check the shared memory allocation on a system
ipcrm: manually deallocate shared memory on a system



取得ipc信息:
ipcs [-m|-q|-s]
-m       输出有关共享内存(shared memory)的信息
-q       输出有关信息队列(message queue)的信息
-s       输出有关“遮断器”(semaphore)的信息

删除ipc(清除共享内存信息)
ipcrm -m|-q|-s shm_id

查看与修改共享内存配置

Finding out shared memory kernel settings in FreeBSD: 

sys1# sysctl -a | grep -i SHM 
kern.ipc.shmmax: 4194304 
kern.ipc.shmmin: 1 
kern.ipc.shmmni: 96 
kern.ipc.shmseg: 64 
kern.ipc.shmall: 1024 
kern.ipc.shm_use_phys: 0



以root身份进行修改 /etc/sysctl.conf 这个文件,加入以下的语句:

kernel.shmmax = 2147483648
kernel.shmmni = 4096
kernel.shmall = 2097152
kernel.sem = 250 32000 100 128
fs.file-max = 65536
net.ipv4.ip_local_port_range = 1024 65000



注:
sem  4个参数依次为SEMMSL(每个用户拥有信号量最大数);
SEMMNS(系统信号量最大数);
SEMOPM(每次semopm系统调用操作数);
SEMMNI(系统辛苦量集数最大数)。
Shmmax 最大共享内存2GB 
物理内存如果小的话可以设置成 536870912。
Shmmni 最小共享内存 4096KB。
Shmall 所有内存大小

一般情况下可以设置最大共享内存为物理内存的一半,如果物理内存是 2G,则可以设置最大共享内存为 1073741824,如上;如物理内存是 1G,则可以设置最大共享内存为 512 * 1024 * 1024 = 536870912;以此类推。
在redhat上最大共享内存不建议超过 4*1024*1024*1024-1=4294967295
设置完成后用命令 more /etc/sysctl.conf |grep kernel.s 检查
建议重启系统再继续下面的操作。

测试与比较

<?php
/*
*读写磁盘文件 和 读写内存比价
*/
echo '阿里云1核2G Ubuntu(64)<br />';
test_dm(1000);
//test_dm(2000);
//test_dm(3000);
function test_dm($loop = 1)
{
@unlink('data_out_memory.txt');
@unlink('data_out_disk.txt');
@unlink('data_in.txt');
$test_result = '<br />相同条件下循环'.$loop.'次运算时间'.PHP_EOL.'<br />';
//写磁盘文件
$start = microtime_float();
//$test_result .= '写磁盘文件开始'.$start.PHP_EOL.'<br />';
for($i=1; $i<=$loop; $i++){
$data_in = 'abcdefghijklmnopqrstuvwxyz1234567890';
@file_put_contents('data_in.txt',$data_in,FILE_APPEND);
}
$end = microtime_float();
//$test_result .= '写磁盘文件结束'.$end.PHP_EOL.'<br />';
$test_result .= '写磁盘耗时:'.($end - $start).PHP_EOL.'<br />';
//读磁盘文件
$start = microtime_float();
//$test_result .= '读磁盘开始'.$start.PHP_EOL.'<br />';
for($i=1; $i<=$loop; $i++){
$data_out .= @file_get_contents('data_disk_read.txt');
}
$end = microtime_float();
//$test_result .= '读磁盘结束'.$end.PHP_EOL.'<br />';
$test_result .= '读磁盘耗时:'.($end - $start).PHP_EOL.'<br />';
//转存读取数据 测试完整性
@file_put_contents('data_out_disk.txt',$data_out);
//写内存
$start = microtime_float();
//$test_result .= '写内存文件开始'.$start.PHP_EOL.'<br />';
for($i=1; $i<=$loop; $i++){
$data_in = 'abcdefghijklmnopqrstuvwxyz1234567890';
$shmid = shmop_open($i, 'c', 0755, 100);
shmop_write($shmid, $data_in, 0);
shmop_close($shmid);
}
$end = microtime_float();
//$test_result .= '写内存文件结束'.$end.PHP_EOL.'<br />';
$test_result .= '写内存耗时:'.($end - $start).PHP_EOL.'<br />';
//读内存
$start = microtime_float();
//$test_result .= '读内存文件开始'.$start.PHP_EOL.'<br />';
for($i=1; $i<=$loop; $i++){
$shmid = shmop_open($i, 'c', 0755, 100);
$data_out.= shmop_read($shmid, 0, 32).'\r\n';
shmop_close($shmid);
}
$end = microtime_float();
//$test_result .= '读内存文件结束'.$end.PHP_EOL.'<br />';
$test_result .= '读内存耗时:'.($end - $start).PHP_EOL.'<br />';
//转存读取数据 测试完整性
@file_put_contents('data_out_memory.txt',$data_out);
//DEBUG 输出测试结果
echo $test_result;
}
function microtime_float()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
?>


基于PHP共享内存, 任务消息队列示例

<?php
/*
* 基于PHP共享内存, 任务消息队列示例
*/
$token = create_token();
//DEBUG 进队列 返回内存地址
$systemid = queue_in($token,$queue_length=10);
//DEBUG 出队列 注销内存地址
queue_out($token,$systemid);
/*
*唯一标记token
*@return token
*/
function create_token() {    
$token = $_SERVER['HTTP_USER_AGENT'].$_SERVER['REMOTE_ADDR'].microtime().rand();    
return '#'.sha1($token);
}
/*
* DEBUG 进队列 队列满则返回等待
* @pram $token 用户唯一标记
* @pram $queue_length 队列长度
* @return 0 队列满 等待进队列; 大于 1 表示返回内存地址
*/
function queue_in($token,$queue_length=10){
$systemid = 0; // System ID for the shared memory segment
$mode = "c"; // Access mode
$permissions = 0755; // Permissions for the shared memory segment
$size = 100; // Size, in bytes, of the segment
for($systemid=1; $systemid <= $queue_length; $systemid++){
$shmid = shmop_open($systemid, $mode, $permissions, $size);
$is_empty = shmop_read($shmid, 0, 1);
if('#' != $is_empty){
shmop_write($shmid, $token, 0);
return $systemid;
}
shmop_close($shmid);
}
return 0;
}
 
/*
* DEBUG 出队列
* @pram $token 用户唯一标记
* @pram $systemid 内存地址
*/
function queue_out($token,$systemid=0){
$mode = "c"; // Access mode
$permissions = 0755; // Permissions for the shared memory segment
$size = 100; // Size, in bytes, of the segment
$shmid = shmop_open($systemid, $mode, $permissions, $size);
shmop_delete($shmid);
shmop_close($shmid);
}
function microtime_float()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
?>


回帖
  • 消灭零回复

微信二维码

微信二维码

微信扫码添加微信好友