对于php 的 sleep理解

今天知乎上有人邀请我回答一个问题,问题挺好的。这里分享下。

问题描述是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
比如 我现在有一个方法: a 调用方法:b
b里面是sleep
1分钟之后
向数据库插入一条数据

用户x在1点的时候 访问了方法a

用户y在1点0分30秒的时候 访问了方法a

请问:最终 到1点1分30秒的时候 ,数据库会插入一条数据 ? 还是两条数据?

为什么

我的答案:

谢邀

我通过代码来对你讲解吧。

1
2
3
4
5
6
7
8
9
<?php

echo date('Y-m-d H:i:s', time());

echo "<br>";

sleep(30);

echo date('Y-m-d H:i:s', time());

然后我打开两个页面,同时去请求我的脚本。

结果如下:

看到没?这两次请求都有对应的输出对吧(相当于向数据库里面插入信息)。

重点来了

我明明是同时请求浏览器的,为什么第二次请求被处理的时间是:

1
2018-03-31 01:07:35

好像是第一次请求被处理完之后结束的时间对吧。

为什么?因为我只开了一个PHP的worker进程:

这意味着什么呢?

因为第一次请求导致了worker进程被挂起了(因为sleep的原因,worker进程处于阻塞态)。所以,此时的worker进程不能去处理客户端的连接。因此,必须等到了第一次请求被处理完了,才可以处理第二次请求。于是第二次请求它被处理的时间是第一次请求被处理完的结束时间。

那么,既然worker进程阻塞了,为什么可以处理实际上在2018-03-31 01:07:05就发来的第二次请求呢(第二次请求和第一次请求是同时发起的)?原因是有Web服务,例如我这里的Nginx。它会去保持Nginx于客户端的连接。所以第二次请求可以推迟到2018-03-31 01:07:35再被处理。其实,如果你把我上面代码的sleep时间设置更久一点,例如:

1
sleep(60);

你会发现,第二次请求很可能会得到一个404状态。

好的,说了这么多,现在回到你的问题。

你是让用户x在1点的时候去请求PHP脚本。然后这时候调用了sleep方法对吧(sleep一分钟)。根据上面我的讲解,worker进程需要等到1点1分才可以去处理用户y实际在1点0分30秒的时候就发来的请求。然后,在1点1分的时候,worker因为sleep而在此被阻塞。直到1点2分才被唤醒,从阻塞态再到就绪态然后才处于可执行状态。然后才可以插入第二条数据。也就是说,到了1点2分的时候,数据库里面才会有第二条数据。

所以,在1点1分30秒的时候,数据库里面只有一条数据

但是,我前面的结论都是在单个worker进程的基础上得到的。如果你的worker进程有多个,假设2个好吧。那么第一个worker进程因为第一次请求在1点钟被阻塞了(直到1点1分第1个worker进程才会被唤醒,然后插入数据)。OK,之后时间到了1点0分30秒,第二个请求发来了,因为第一个worker此时还是处于阻塞态,所以第二个worker进程会去处理这个请求。同样的,第二个worker进程在1点0分30秒被阻塞了(直到1点1分30秒第二个worker进程才会被唤醒,然后插入第二条数据)。因此,最终在1点1分30秒的时候,数据库里面是有两条数据的。

所以在1点1分30秒的时候,数据库里面有几条记录,看情况。