本文目录导读:

PHP 中有多种共享内存的实现方式,从简单到复杂,我来详细介绍:
PHP 原生共享内存函数(最简单)
// 创建或打开共享内存段 $shm_id = shmop_open(0x1234, 'c', 0644, 1024); // 创建1KB的共享内存 // 写入数据 $data = "Hello, shared memory!"; shmop_write($shm_id, $data, 0); // 读取数据 $content = shmop_read($shm_id, 0, shmop_size($shm_id)); // 删除共享内存 shmop_delete($shm_id); // 关闭连接 shmop_close($shm_id);
System V 共享内存(推荐)
// 创建或访问共享内存
$shm_key = ftok(__FILE__, 't'); // 生成唯一key
$shm_id = shm_attach($shm_key, 1024, 0666); // 附加到共享内存
// 存储变量
if (shm_has_var($shm_id, 1)) {
echo "Key 1 exists: " . shm_get_var($shm_id, 1);
} else {
shm_put_var($shm_id, 1, array(
'time' => time(),
'data' => 'test'
));
}
// 移除变量
shm_remove_var($shm_id, 1);
// 分离共享内存
shm_detach($shm_id);
// 删除共享内存段
shm_remove($shm_id);
使用 APCu 扩展(缓存型)
// 写入缓存
apcu_store('user_data', $data, 3600); // 缓存1小时
// 读取缓存
$data = apcu_fetch('user_data');
// 删除缓存
apcu_delete('user_data');
// 判断是否存在
if (apcu_exists('user_data')) {
echo "Key exists";
}
使用 Redis 作为共享存储(分布式)
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 写入数据
$redis->set('shared_key', $data);
// 读取数据
$data = $redis->get('shared_key');
// 队列操作
$redis->lPush('queue', 'task1');
$task = $redis->rPop('queue');
完整示例:多进程计数器
<?php
class SharedCounter {
private $shm_id;
private $sem_id;
public function __construct() {
$key = ftok(__FILE__, 'c');
// 创建信号量用于互斥
$this->sem_id = sem_get($key, 1, 0666, 1);
// 创建共享内存(8字节用于存整数)
$this->shm_id = shm_attach($key, 1024, 0666);
if (!shm_has_var($this->shm_id, 1)) {
shm_put_var($this->shm_id, 1, 0);
}
}
public function increment() {
sem_acquire($this->sem_id);
$count = shm_get_var($this->shm_id, 1);
$count++;
shm_put_var($this->shm_id, 1, $count);
sem_release($this->sem_id);
return $count;
}
public function get() {
return shm_get_var($this->shm_id, 1);
}
public function reset() {
sem_acquire($this->sem_id);
shm_put_var($this->shm_id, 1, 0);
sem_release($this->sem_id);
}
public function __destruct() {
shm_detach($this->shm_id);
}
}
// 使用示例
$counter = new SharedCounter();
// fork多个进程测试
for ($i = 0; $i < 5; $i++) {
$pid = pcntl_fork();
if ($pid == 0) {
// 子进程
for ($j = 0; $j < 10; $j++) {
$counter->increment();
}
exit(0);
}
}
// 等待所有子进程完成
while (pcntl_waitpid(0, $status) != -1);
echo "Final counter: " . $counter->get() . "\n"; // 应该显示50
注意事项
安全访问模式
// 使用锁保护
function withSharedMemory(string $key, callable $callback) {
$shm_key = ftok(__FILE__, 's');
$shm_id = shm_attach($shm_key, 1048576); // 1MB
// 获取锁
sem_acquire($sem_id);
try {
if (!shm_has_var($shm_id, 1)) {
shm_put_var($shm_id, 1, []);
}
$data = shm_get_var($shm_id, 1);
$result = $callback($data);
shm_put_var($shm_id, 1, $data);
return $result;
} finally {
sem_release($sem_id);
shm_detach($shm_id);
}
}
// 使用
$value = withSharedMemory('cache', function(&$data) {
$data['access_time'] = time();
return $data;
});
扩展安装
# 安装 System V 共享内存支持 apt-get install php-sysvmsg php-sysvsem php-sysvshm # 安装 APCu pecl install apcu # 安装 Redis 扩展 pecl install redis
常见应用场景
- 进程间通信:多 worker 进程共享数据
- 缓存:热数据缓存,减少数据库查询
- 计数器:PV/UV 统计
- 配置共享:多进程共享配置信息
- 会话管理:分布式 Session 存储
性能对比
| 方法 | 速度 | 跨进程支持 | 分布式支持 | 复杂度 |
|---|---|---|---|---|
| shmop | 快 | 是 | 否 | 低 |
| System V | 快 | 是 | 否 | 中 |
| APCu | 非常快 | 单进程 | 否 | 低 |
| Redis | 快 | 是 | 是 | 中 |
选择合适的方法取决于你的需求:如果只是单机多进程,System V 共享内存最合适;如果需要分布式,选择 Redis;如果只是进程内缓存,APCu 最合适。