You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP多并发请求场景下如何保证缓存仅生成一次

PHP 单实例缓存并发生成问题修复方案

核心逻辑是通过本地文件独占锁控制并发,保证仅首个请求能执行缓存生成逻辑,其余请求阻塞等待锁释放后直接读取已生成的缓存,避免重复执行耗时的生成逻辑。

修复后完整代码

<?php
$cacheFile = __DIR__ . '/cache.html';
$lockFile = __DIR__ . '/cache_generate.lock';
$source1Path = __DIR__ . '/source1.txt';
$source2Path = __DIR__ . '/source2.xml';

// 首次校验缓存是否有效,有效直接读取返回
$cacheTime = file_exists($cacheFile) ? filemtime($cacheFile) : 0;
if ($cacheTime > filemtime($source1Path) && $cacheTime > filemtime($source2Path)) {
    $content = file_get_contents($cacheFile);
    echo $content;
    exit;
}

// 缓存失效,尝试获取生成锁
$lockFp = fopen($lockFile, 'w+');
// 加独占阻塞锁:拿不到锁的请求会在此处阻塞,直到锁被释放
if (flock($lockFp, LOCK_EX)) {
    // 拿到锁后二次校验缓存是否已被生成:避免等待期间其他请求已完成缓存生成
    clearstatcache(true, $cacheFile); // 清除PHP文件状态缓存,读取最新修改时间
    $cacheTime = file_exists($cacheFile) ? filemtime($cacheFile) : 0;
    if ($cacheTime > filemtime($source1Path) && $cacheTime > filemtime($source2Path)) {
        $content = file_get_contents($cacheFile);
    } else {
        // 执行缓存生成逻辑
        $content = generate_content($source1Path, $source2Path);
        // 写入缓存文件
        file_put_contents($cacheFile, $content);
    }
    // 手动释放锁
    flock($lockFp, LOCK_UN);
}
fclose($lockFp);

// 输出最终内容
echo $content;
?>

可选优化说明

  • 若不需要请求阻塞等待,可将flock($lockFp, LOCK_EX)修改为flock($lockFp, LOCK_EX | LOCK_NB),拿不到锁时直接返回旧缓存或返回「内容生成中」的提示,适合对响应延迟要求高的场景
  • 锁文件无需提前创建,fopen会自动生成,确保站点运行用户对所在目录有读写权限即可
  • PHP进程异常退出时会自动释放文件锁,不会出现死锁问题
  • 以上方案仅适用于单服务器部署场景,分布式部署场景需改用Redis、ETCD等实现分布式锁

内容的提问来源于stack exchange,提问作者Snowy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 22:57:02