PHP 怎么跨进程共享

wen PHP项目 1

本文目录导读:

PHP 怎么跨进程共享

  1. 共享内存(shmop / sysvshm) 🚀
  2. 文件锁(flock) 📁
  3. Redis / Memcached 🔥
  4. 消息队列(Message Queue) 💬
  5. ZeroMQ / 其他IPC 🛠️
  6. 数据库(MySQL/PostgreSQL) 📊
  7. Apache/nginx + 缓存文件 📝
  8. 进程守护 + Swoole/Workerman 🚀
  9. 选择建议 📋
  10. 完整示例:计数器实现 🔄

在 PHP 中实现跨进程共享,主要有以下几种方案,根据你的需求和环境选择:

共享内存(shmop / sysvshm) 🚀

最常见的跨进程通信方式,性能最好。

使用 shmop 扩展(简单版)

<?php
// 创建 100KB 共享内存块
$shm_id = shmop_open(0xFF3, "c", 0644, 100 * 1024);
// 写入数据
$data = json_encode(['user' => 'admin', 'time' => time()]);
shmop_write($shm_id, $data, 0);
// 读取数据(在另一个进程中)
$size = shmop_size($shm_id);
$data = shmop_read($shm_id, 0, $size);
// 关闭
shmop_close($shm_id);
?>

使用 sysvshm 扩展(带信号量)

<?php
// key 必须是整数
$key = ftok('/tmp/test', 'R'); // 或直接指定数字
// 创建信号量(用于同步)
$sem = sem_get($key, 1, 0644, 1);
// 获取共享内存
$shm = shm_attach($key, 1024 * 1024, 0644);
// 锁定
sem_acquire($sem);
// 写入数组
$data = ['key' => 'value', 'count' => 100];
shm_put_var($shm, 1, $data);
// 读取
$result = shm_get_var($shm, 1);
// 解锁和清理
sem_release($sem);
shm_detach($shm);
?>

文件锁(flock) 📁

适用于简单的数据共享,通过文件加锁保证互斥。

<?php
// 写进程
$file = fopen('/tmp/shared_data.txt', 'c+');
flock($file, LOCK_EX);
fseek($file, 0);
ftruncate($file, 0);
fwrite($file, json_encode(['time' => time(), 'data' => 'hello']));
fflush($file);
flock($file, LOCK_UN);
fclose($file);
// 读进程
$file = fopen('/tmp/shared_data.txt', 'r');
flock($file, LOCK_SH);
$data = fread($file, filesize('/tmp/shared_data.txt'));
flock($file, LOCK_UN);
fclose($file);
?>

Redis / Memcached 🔥

网络化的共享方案,适合分布式系统。

<?php
// Redis 示例
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 进程 A
$redis->setex('shared_key', 3600, json_encode(['data' => 'value']));
// 进程 B
$data = $redis->get('shared_key');
echo $data; // {"data":"value"}
?>

消息队列(Message Queue) 💬

适合异步处理和任务分发。

<?php
// 使用 Redis 列表做队列
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 生产者
$redis->lpush('task_queue', json_encode(['task' => 'process', 'id' => 1]));
// 消费者
$task = $redis->rpop('task_queue');
echo $task; // {"task":"process","id":1}
?>

ZeroMQ / 其他IPC 🛠️

适合复杂场景的进程间通信。

<?php
// 需要安装 zmq 扩展
$context = new ZMQContext();
$socket = $context->getSocket(ZMQ::SOCKET_REP, 'my_persistent_id');
$socket->bind("tcp://*:5555");
// 接收消息
$message = $socket->recv();
$socket->send("Response");
// 另一进程连接
$reqSocket = $context->getSocket(ZMQ::SOCKET_REQ);
$reqSocket->connect("tcp://localhost:5555");
$reqSocket->send("Hello");
$reply = $reqSocket->recv();
?>

数据库(MySQL/PostgreSQL) 📊

最通用的方案,但性能最差。

<?php
// 使用数据库做状态共享
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$pdo->exec("CREATE TABLE IF NOT EXISTS shared_state (
    key VARCHAR(50) PRIMARY KEY,
    value TEXT,
    updated_at TIMESTAMP
)");
// 写入
$pdo->prepare("INSERT INTO shared_state (key, value, updated_at) VALUES (?, ?, NOW())
    ON DUPLICATE KEY UPDATE value = ?, updated_at = NOW()")
    ->execute(['counter', 100, 100]);
// 读取
$stmt = $pdo->prepare("SELECT value FROM shared_state WHERE key = ?");
$stmt->execute(['counter']);
$value = $stmt->fetchColumn();
?>

Apache/nginx + 缓存文件 📝

简单且常用,通过临时文件系统。

<?php
// 使用 /tmp 目录 + 唯一文件名
$lock_key = md5('my_shared_data');
$cache_file = sys_get_temp_dir() . '/' . $lock_key . '.cache';
// 原子写入
$data_to_write = json_encode(['time' => time()]);
$tmp_file = $cache_file . '.' . uniqid();
file_put_contents($tmp_file, $data_to_write);
rename($tmp_file, $cache_file);  // 原子操作
// 读取
if (file_exists($cache_file)) {
    $data = json_decode(file_get_contents($cache_file), true);
}
?>

进程守护 + Swoole/Workerman 🚀

使用常驻内存方案,天然共享。

<?php
// Swoole 示例
$server = new Swoole\Http\Server('0.0.0.0', 9501);
$server->on('start', function() {
    // 全局变量在所有 worker 中共享
    Swoole\Table::getInstance()->create('connections', 1024);
});
$server->on('request', function($request, $response) {
    // 写入共享表
    $table = Swoole\Table::getInstance('connections');
    $table->set($request->fd, ['data' => 'value']);
    // 读取
    $data = $table->get($request->fd);
    $response->end(json_encode($data));
});
?>

选择建议 📋

方案 性能 适用场景 复杂度
共享内存 高性能本地IPC 中等
文件锁 简单数据共享
Redis 分布式系统 中等
消息队列 异步任务 中等
数据库 持久化状态

完整示例:计数器实现 🔄

<?php
// 使用 Redis 实现一个安全的计数器
class Counter {
    private $redis;
    public function __construct() {
        $this->redis = new Redis();
        $this->redis->connect('127.0.0.1', 6379);
    }
    // 原子递增
    public function increment($key) {
        return $this->redis->incr($key);
    }
    // 带过期时间的锁
    public function withLock($key, $callback) {
        $lock_key = "lock:$key";
        while (!$this->redis->set($lock_key, 1, ['NX', 'EX' => 10])) {
            usleep(100000); // 等待 100ms
        }
        try {
            return $callback();
        } finally {
            $this->redis->del($lock_key);
        }
    }
}
// 使用示例
$counter = new Counter();
$counter->increment('page_views');
echo "总访问数: " . $counter->withLock('data', function() {
    return $counter->increment('total');
});
?>

选择方案时考虑:

  • 数据大小:大容量数据用共享内存
  • 数据持久性:需要持久化用数据库/Redis
  • 分布式部署:用 Redis/MQ
  • 性能要求:高并发用共享内存/Redis
  • 简单性:文件系统最简单但功能有限

抱歉,评论功能暂时关闭!