PHP的sleep()有什么实际用途?

53

我刚刚查看了sleep()的文档。

你会在哪里使用这个函数?

它是否用于在昂贵的函数中给 CPU 一个休息时间?

有什么常见的陷阱吗?

13个回答

53

它找到应用的其中一个场景是创建一个延迟

假设您已经构建了一个使用curl/file_get_contents获取远程页面的爬虫。现在,您不希望在短时间内向远程服务器发送太多请求。因此,您在连续请求之间引入了一个延迟。

sleep接受以秒为单位的参数,它的朋友usleep接受以微秒为单位的参数,在某些情况下更加适合。


1
除非有其他用途,否则我只能想到这个,那就是将php放在Web服务器上。 - Frank
4
更普遍的说法是:限制请求频率,包括进入和离开两个方面。 - deceze
我在上传文件到服务器后使用 sleep 来确保文件完全上传。如果没有它,脚本将会失败。 - Vahid Amiri
1
sleep 返回 0 表示成功,但 usleep 不会告诉你任何信息。只是想把它包含进来!在使用任何东西之前,请注意 xD。 - Tilak Madichetti

34
另一个例子:您正在运行某种批处理过程,它大量使用资源。也许您正在遍历900万本书的数据库并更新其中约10%。该过程必须在白天运行,但要做的更新太多,以至于运行批处理程序会使数据库服务器崩溃并影响其他用户的使用体验。
因此,您修改批处理过程,以便提交1000个更新,然后sleep 5秒钟,以给数据库服务器完成处理已积压的其他用户请求的机会。

26

这是我在一个项目中使用sleep的一小段代码:

foreach($addresses as $address)
{
  $url = "http://maps.google.com/maps/geo?q={$address}&output=json...etc...";
  $result = file_get_contents($url);
  $geo = json_decode($result, TRUE);

  // Do stuff with $geo

  sleep(1);
}

在这种情况下,sleep帮助我防止被Google地图阻塞,因为我向服务器发送了太多的请求。


10

虽然这是一个老问题,但使用 u/sleep 的另一个原因可能是在编写安全/加密代码时,例如身份验证脚本。以下是一些例子:

  1. 您可能希望通过使登录脚本故意变慢,特别是在几次失败的尝试后,来减少潜在暴力攻击的效果。
  2. 此外,您可能希望在加密过程中添加人为延迟,以减轻时间攻击的影响。我知道在像 PHP 这样的语言中编写如此深入的加密代码的机会很小,但我认为这仍然是有效的。

编辑

使用 u/sleep 对抗时间攻击并不是一个好的解决方案。在时间攻击中,您仍然可以获取重要数据,只需要更多的样本来滤除 u/sleep 添加的噪声。

您可以在 随机睡眠可以防止时间攻击吗? 中找到有关此主题的更多信息。


这不是防止此类攻击的最佳实践。它会导致您的脚本保持执行状态,占用内存和资源。更好的方法是在应用程序中实现客户端延迟,然后自动关闭任何不遵守延迟的请求。服务器端延迟为DOS攻击提供了一个简单的向量。人工延迟也不是防止时间攻击的最佳实践:使用时间安全比较函数更安全,通常使用更少的资源。 - cazort
关于时序攻击,请参考ircmaxell在您链接的页面上给出的答案,其中提到了随机休眠以防止时序攻击,它详细解释了我对这些攻击的看法。 - cazort
如果未来的丹能够回到过去,告诉正在编写这个答案的过去的丹有用的东西,那就是:“永远不要编写自己的安全/密码代码”。 - Angry Dan

2
这是一个有点奇怪的情况...文件传输限速。
在我们很久以前运行的文件传输服务中,文件是从10Mbps上行服务器提供的。为了防止网络过载,下载脚本跟踪同时下载的用户数量,然后计算每个用户每秒可以发送多少字节。它会发送部分此数量,然后休眠一会儿(我想是1/4秒),然后发送更多...等等。
通过这种方式,服务器连续运行在约9.5Mbps的速度,而没有上行饱和问题...并且始终动态调整下载速度。
我现在不会这样做,也不会用PHP来做...但当时它效果很好。

2

另一种使用方法:如果您想更频繁地执行cronjob,甚至每分钟执行一次。我使用以下代码:

sleep(30);
include 'cronjob.php';

我会把这个文件和cronjob.php每分钟调用一次。

1
我通常不会用它来提供网页服务,但对于命令行脚本非常有用。
$ready = false;
do {
  $ready = some_monitor_function();
  sleep(2);
} while (!$ready);

1

这篇文章发表已经很久了,但我仍会进行评论。 最近我不得不检查一个非常长时间运行的进程,该进程创建了一些文件。因此,我编写了一个函数来遍历cURL函数。如果我正在寻找的文件不存在,则我暂停php文件,并稍后再次检查:

function remoteFileExists() {
    $curl = curl_init('domain.com/file.ext');

    //don't fetch the actual page, you only want to check the connection is ok
    curl_setopt($curl, CURLOPT_NOBODY, true);

    //do request
    $result = curl_exec($curl);

    //if request did not fail
    if ($result !== false) {
        //if request was ok, check response code
        $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);  

        if ($statusCode == 404) {
              sleep(7);
              remoteFileExists();
        }
        else{
            echo 'exists'; 
        }
    }

    curl_close($curl);

}

echo remoteFileExists();

1

您可以使用sleep来暂停脚本执行...例如延迟服务器端的AJAX调用或实现观察者。您还可以使用它来模拟延迟。

我也使用它来延迟sendmail()和其他操作。

有些人使用sleep()来防止DoS和登录暴力破解,但我不同意,因为您需要添加一些检查来防止用户多次运行。

还请查看usleep


1
最近我在使用谷歌的地理位置API时,不得不用到了它。由于循环中的每个地址都需要调用谷歌的服务器,因此需要一些时间才能收到响应。我使用了usleep(500000)来给所有相关的东西足够的时间。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接