1. 云栖社区>
  2. PHP教程>
  3. 正文

PHP session并发及session读写锁

作者:用户 来源:互联网 时间:2017-12-01 10:04:04

cookie技术程序设计记录

PHP session并发及session读写锁 - 摘要: 本文讲的是PHP session并发及session读写锁, PHP这门程序设计语言简单得令人发指,那是因为PHP的作者们太神通。今天我来谈谈所有的phper都熟悉的session(会话)。 早在几年前我就记录了两篇学习笔记: PHP session和cookie技术 PHP自定义会话数据储存

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

早在几年前我就记录了两篇学习笔记:

PHP session和cookie技术

PHP自定义会话数据储存,PHP会话数据储存到MYSQL

从那以后,已然觉得已经100%掌握,那咱们来看看下面的表象(测试的代码贴到最后了):

需要说明的是:

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 session并发及session读写锁

第二次访问:

PHP session并发及session读写锁

请求:/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 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

<?phpfinal class SessionController extends /Yaf/Controller_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 = /Core/Factory::session();		$session->set('user_name', 'xudianyang');		$session->set('user_id', '123');		sleep(3);		echo json_encode($_SESSION);		return false;	}	public function setLoginRedisAction()	{		$session = /Core/Factory::session();		$session->set('last_time', time());		echo json_encode($_SESSION);		return false;	}	public function indexRedisAction()	{		// Auto Rend View	}	public function getSessionRedisAction()	{		$session = /Core/Factory::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>

以上是云栖社区小编为您精心准备的的内容,在云栖社区的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索cookie , 技术 , 程序设计 记录 ,以便于您获取更多的相关知识。

弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率

40+云计算产品,6个月免费体验

现在注册,免费体验40+云产品,及域名优惠!

云服务器9.9元/月,大学必备