PHP Session阻塞验证

function.session-start看到,session_start后,会一直持有锁,建议使用session_write_close/session_commit释放锁,对此表示有点意外,因为这个session_start函数名字取得作实不咋地,怎么看也不想是一段加锁函数,于是写一段代码来验证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
print_r(date('h:i:s')." enter<br>");
session_start();
print_r(date('h:i:s')." start in session sleep<br>");
$_SESSION['a'] = date('h:i:s');
sleep(10);
print_r(date('h:i:s')." end in session sleep<br>");
// $_SESSION can still be read, but writing will not update the session.
// the lock is removed and other scripts can now read the session
session_write_close(); //别名session_commit
print_r(date('h:i:s')." start after session write sleep<br>");
sleep(10);
print_r(date('h:i:s')." end after session write sleep<br>");
?>

Chrome上同时(1秒左右的延迟)打开四个页面。

第一个页面(有0s的Stalled时间,TTFB是20s,总共是20.02s):

1
2
3
4
5
01:06:31 enter
01:06:31 start in session sleep
01:06:41 end in session sleep
01:06:41 start after session write sleep
01:06:51 end after session write sleep

第二个页面(有19.34s的Stalled时间,TTFB是29.99s,总共是49.35s):

1
2
3
4
5
01:06:51 enter
01:07:01 start in session sleep
01:07:11 end in session sleep
01:07:11 start after session write sleep
01:07:21 end after session write sleep

第三个页面(有18.53s的Stalled时间,TTFB是20s,总共是38.54s):

1
2
3
4
5
01:06:51 enter
01:06:51 start in session sleep
01:07:01 end in session sleep
01:07:01 start after session write sleep
01:07:11 end after session write sleep

第四个页面(有16.75s的Stalled时间,TTFB是39.99s,总共是56.77s):

1
2
3
4
5
01:06:51 enter
01:07:11 start in session sleep
01:07:21 end in session sleep
01:07:21 start after session write sleep
01:07:31 end after session write sleep

Chrome会在同域的第一个请求返回后,再并发开始其他的请求(有最大并发值)。所以,后面三个页面,虽然我点开时间有秒级的差别,实际开始时间都是第一个页面返回后的时间。当后面三个页面同时进入后端APACHE后(后端没有排队),可以看到enter时间是一致的。
差别就在于“start in session sleep”。

  1. 第三个页面顺利进入后优先抢到锁,在01:07:01释放后。
  2. 第二个页面抢到锁,sesion_start返回,直到 01:07:11才释放锁。
  3. 第四个页面终于获得锁,直到01:07:21才释放锁。

如上验证,session_start之后,如果不session_write_close,的确会Block其他进程调用session_start

将上述session_start修改为session_start([‘read_and_close’ => true]) 后,现象依旧。