首页 > php教程 > PHP源码 > 正文

PHP session并发及session读写锁分析

php中文网
发布: 2016-06-08 17:20:57
原创
1336人浏览过

关于PHP session并发及session读写锁问题估计各大程序员都不会想到这个问题,因为一般情况我们不会使用session来做并发操作了,但有时也有可能用到,下面整理一个session并发及session读写锁文章供各位参考。

<script>ec(2);</script>

php这门程序设计语言简单得令人发指,那是因为php的作者们太神通。今天我来谈谈所有的phper都熟悉的session(会话)。

需要说明的是:

1.示例代码中分别以files,redis储存会话数据
2./session/setUserFile和/session/setUserRedis设置user_name,user_id两个key,并sleep了3s
3./session/setLoginFile和/session/setLoginRedis设置last_time一个key

4./session/indexFile和/session/indexRedis模板中两个ajax请求,/session/setUserFile和/session/setUserRedis立即执行,/session/setLoginFile和/session/setLoginRedis延迟300ms,是为了模拟同一个用户,同时在两个页面(请求)修改会话数据

执行结果表象:

请求:/session/indexfile

第一次访问:

立即学习PHP免费学习笔记(深入)”;

PHP session并发及session读写锁分析

第二次访问:

PHP session并发及session读写锁分析

自学 PHP、MySQL和Apache
自学 PHP、MySQL和Apache

本书将PHP开发与MySQL应用相结合,分别对PHP和MySQL做了深入浅出的分析,不仅介绍PHP和MySQL的一般概念,而且对PHP和MySQL的Web应用做了较全面的阐述,并包括几个经典且实用的例子。 本书是第4版,经过了全面的更新、重写和扩展,包括PHP5.3最新改进的特性(例如,更好的错误和异常处理),MySQL的存储过程和存储引擎,Ajax技术与Web2.0以及Web应用需要注意的安全

自学 PHP、MySQL和Apache 400
查看详情 自学 PHP、MySQL和Apache
请求:/session/getsessionfile
array(3) { ["user_name"]=> string(10) "xudianyang" ["user_id"]=> string(3) "123" ["last_time"]=> int(1419411695) }
以文件保存会话数据结论:/session/setUserFile执行时间为3.1s,/session/setLoginFile执行时间为2.81s(如果加上ajax延迟刚好两个请求的响应时间都是3.1s)

请求:/session/indexredis

第一次访问:

立即学习PHP免费学习笔记(深入)”;

PHP session并发及session读写锁分析

第二次访问:

PHP session并发及session读写锁分析
请求:/session/getsessionredis
array(2) { ["user_name"]=> string(10) "xudianyang" ["user_id"]=> string(3) "123" }
为什么?

手册中有这样的描述:

void session_write_close ( void )

End the current session and store session data.

Session data is usually stored after your script terminated without the need to call session_write_close(), but as session data is locked to prevent concurrent writes only one script may operate on a session at any time. When using framesets together with sessions you will experience the frames loading one by one due to this locking. You can reduce the time needed to load all the frames by ending the session as soon as all changes to session variables are done.

也就是说session是有锁的,为防止并发的写会话数据。php自带的的文件保存会话数据是加了一个互斥锁(session_start()的时候),从而解释了上面呈现的两个请求响应时间相同。但是以redis保存会话数据时,第二个ajax虽然没有阻塞,但是会话数据并没有写入到redis,那我们追溯一下源码就有答案了。

php-5.4.14源码
默认的files的save_handler
php-5.4.14/ext/session/mod_files.c
PHP session并发及session读写锁分析
redis的save_handler
phpredis中的redis_session.c中并无实现session读写锁的机制,那上述如何解释呢?其实如果我们将session的源码大致浏览一下,就可以解释了。因为会话在session_start之后,将会话数据就会读取到$_SESSION(在扩展内部全局变量PS(http_session_vars))中,在PHP_RSHUTDOWN_FUNCTION(session)(请求释放)时,通过php_session_flush(TSRMLS_C)将会话数据写入储存介质,也就是说会话的数据并不是实时写入到储存介质的。
这就解释了,为什么redis保存会话数据时,/session/setLoginRedis看似未将last_time写入到redis,实质是写了,但是当/session/setUserRedis请求释放时(由于最开始会话数据中并无last_time这个key),要将所有的会话数据写入到储存介质,从而覆盖了/session/setLoginRedis请求写的值,到此解释了上述的问题。
测试代码:
Session.php
<table width="620" align="center" border="0" cellpadding="1" cellspacing="1"  style="background:#FB7">
	  <tr>
		<td width="464" height="27" bgcolor="#FFE7CE"> 代码如下</td>
		<td width="109" align="center" bgcolor="#FFE7CE" style="cursor:pointer;" onClick="doCopy('copy7241')">复制代码</td>
	  </tr>
	  <tr>
		<td height="auto" colspan="2" valign="top" bgcolor="#FFFFFF" style="padding:10px;" class="copyclass" id=copy7241><pre class="brush:php;toolbar:false;" title=""><?php

final class SessionController extends YafController_Abstract
{
    public function setUserFileAction()
    {
        session_start();
        $_SESSION['user_name'] = 'xudianyang';
        $_SESSION['user_id']   = '123';

        sleep(3);
        echo json_encode($_SESSION);
        return false;
    }

    public function setLoginFileAction()
    {
        session_start();
        $_SESSION['last_time'] = time();

        echo json_encode($_SESSION);
        return false;
    }

    public function indexFileAction()
    {
        // Auto Rend View
    }

    public function getSessionFileAction()
    {
        session_start();
        var_dump($_SESSION);

        return false;
    }

    public function setUserRedisAction()
    {
        $session = CoreFactory::session();
        $session->set('user_name', 'xudianyang');
        $session->set('user_id', '123');

        sleep(3);
        echo json_encode($_SESSION);
        return false;
    }

    public function setLoginRedisAction()
    {
        $session = CoreFactory::session();
        $session->set('last_time', time());

        echo json_encode($_SESSION);
        return false;
    }

    public function indexRedisAction()
    {
        // Auto Rend View
    }

    public function getSessionRedisAction()
    {
        $session = CoreFactory::session();
        var_dump($_SESSION);

        return false;
    }
}
登录后复制
indexfile.phtml
<!DOCTYPE html>
<html>
<head>
  <title>测试session并发锁问题</title>
  <meta charset="utf-8">
  <script type="text/javascript" src="/assets/js/jquery-1.10.2.min.js"></script>
  <script type="text/javascript">
      $.ajax({
          url: "/session/setUserFile",
          type: "get",
          dataType: "json",
          success: function(response){
              console.info(response.last_time);
          }
      });
      setTimeout(function(){
          $.ajax({
              url: "/session/setLoginFile",
              type: "get",
              dataType: "json",
              success: function(response){
                  console.info(response.last_time);
              }
          });
      }, 300);
  </script>
</head>
<body>
同时发起2两个ajax请求
</body>
</html>
登录后复制
indexredis.phtml
<!DOCTYPE html>
<html>
<head>
  <title>测试session并发锁问题</title>
  <meta charset="utf-8">
  <script type="text/javascript" src="/assets/js/jquery-1.10.2.min.js"></script>
  <script type="text/javascript">
      $.ajax({
          url: "/session/setUserRedis",
          type: "get",
          dataType: "json",
          success: function(response){
              console.info(response.last_time);
          }
      });
      setTimeout(function(){
          $.ajax({
              url: "/session/setLoginRedis",
              type: "get",
              dataType: "json",
              success: function(response){
                  console.info(response.last_time);
              }
          });
      }, 300);
  </script>
</head>
<body>
同时发起2两个ajax请求
</body>
</html>
登录后复制
相关标签:
PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号