php实现原子操作
PHP实现原子操作的方法
原子操作指在多线程或并发环境下不可分割的操作,确保操作要么完全执行,要么完全不执行。PHP作为脚本语言,原生不支持多线程,但在并发场景(如Web请求、CLI脚本)中仍需处理共享资源的原子性问题。
使用文件锁(flock)
文件锁是PHP中实现原子操作的常见方式,适用于单机环境。通过flock函数对文件进行独占锁定,确保同一时间只有一个进程能访问共享资源。

$fp = fopen("lockfile.lock", "w+");
if (flock($fp, LOCK_EX)) { // 获取独占锁
// 执行原子操作(如写入文件、更新数据库)
flock($fp, LOCK_UN); // 释放锁
} else {
// 获取锁失败处理
}
fclose($fp);
使用Redis事务或Lua脚本
在分布式环境中,Redis的原子操作能力更可靠。通过MULTI/EXEC事务或Lua脚本实现复杂操作的原子性。

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 方式1:事务
$redis->multi();
$redis->incr('counter'); // 原子递增
$redis->exec();
// 方式2:Lua脚本
$script = "return redis.call('INCR', KEYS[1])";
$redis->eval($script, ['counter'], 1);
数据库事务与乐观锁
对于数据库操作,结合事务与版本号(乐观锁)实现原子更新。
$pdo = new PDO("mysql:host=localhost;dbname=test", "user", "pass");
$pdo->beginTransaction();
try {
// 查询当前版本号
$stmt = $pdo->query("SELECT version FROM products WHERE id = 1");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
// 带版本号更新
$affected = $pdo->exec("UPDATE products SET stock = stock - 1, version = version + 1
WHERE id = 1 AND version = {$row['version']}");
if ($affected === 0) {
throw new Exception("并发冲突");
}
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
}
信号量(Semaphore)扩展
安装sysvsem扩展后,可使用System V信号量实现进程间同步。
$semKey = ftok(__FILE__, 't');
$semId = sem_get($semKey);
if (sem_acquire($semId)) { // 阻塞直到获取信号量
// 原子操作区域
sem_release($semId); // 释放
}
注意事项
- 文件锁不适用于高并发场景,可能成为性能瓶颈。
- Redis方案需处理网络分区问题,必要时使用Redlock等分布式锁算法。
- 数据库乐观锁适用于冲突较少的场景,冲突频繁时考虑悲观锁(
SELECT FOR UPDATE)。 - 原子操作应尽量简短,避免长时间占用资源导致阻塞。






