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

单脚本发起多XHR请求至同一PHP文件的会话创建问题咨询

单脚本发起多XHR请求至同一PHP文件的会话创建问题咨询

嘿,抱歉再叨扰一次,但这次我碰到了个新疑问😅

我现在有个PHP文件是这么写的:

<?php  
session_start(); 
$_SESSION['globalVar'] = "undefined";  

if (!empty($_POST['triggerLoop'])) {  
    for ($x = 0; $x < 5; $x++) {  
        $_SESSION['globalVar'] = getResult();  
        sleep(1);              
    }  
}  

//------------------------------------------------------ 
//Listen 
if (!empty($_POST['listen'])) {  
    // 我本来打算在这里读取 $_SESSION['globalVar'] 并返回给前端
}

情况是这样:我用前端发起了多个XHR请求,一个请求触发triggerLoop分支(这个分支会跑5秒,每一秒更新一次session里的globalVar),同时我不断发起listen请求想实时获取globalVar的最新值,但结果要么是listen请求一直卡着直到triggerLoop跑完才返回,要么只能拿到最后一次更新的值,根本看不到中间的变化。这到底是哪里出问题了呀?


哈哈,这个问题太常见了!核心问题出在PHP默认的session文件锁机制上。

当你的PHP脚本调用session_start()时,PHP会自动锁定对应的session文件——这个锁会一直持有到整个请求执行完毕,或者你主动调用session_write_close()释放它。所以你的triggerLoop请求一旦启动,就会攥着session锁跑满5秒,期间所有的listen请求都得排队等这个锁释放才能读取session数据,自然就看不到中间的更新,甚至会被阻塞很久。

给你几个实用的解决办法:

  • 循环里主动释放session锁
    在triggerLoop的每次循环中,更新完session值后立刻调用session_write_close()把数据写入文件并释放锁,下次要更新时再重新开启session。修改后的代码大概是这样:

    if (!empty($_POST['triggerLoop'])) {  
        for ($x = 0; $x < 5; $x++) {  
            session_start(); // 重新开启session以获取锁
            $_SESSION['globalVar'] = getResult();  
            session_write_close(); // 写完立刻释放锁,让其他请求能读取
            sleep(1);              
        }  
    }
    

    这样每次循环更新完就释放锁,listen请求就能及时拿到最新的globalVar值了。

  • 换用非阻塞的session存储
    如果你的项目有条件,可以把session存储换成Redis或者Memcached这类内存数据库。它们的锁机制比文件存储灵活得多,不会因为单个请求长时间占用而阻塞其他请求,而且读写速度也更快。不过这个需要你配置PHP的session驱动,稍微有点动手成本,但长期来看是更优的方案。

  • 优化listen请求的session使用
    要是listen请求只需要读取session数据,那读完之后也立刻调用session_write_close(),别拿着锁不放,这样能进一步减少阻塞的概率。

另外提一句,如果getResult()函数本身有耗时操作,也会拖慢整个流程,不过这就是另一个优化方向啦。

备注:内容来源于stack exchange,提问作者Abb

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 17:39:42