Language agnostic 睡眠有害吗?

Language agnostic 睡眠有害吗?,language-agnostic,Language Agnostic,首先,在许多情况下,Sleep()被误用,例如“同步”线程或定期轮询通知函数将执行的值(例如在Win32WaitForSingleObject中) 但是其他用例呢睡眠总是有害的吗?如果不是,那么睡眠的好用例是什么?如果是,为什么几乎所有语言都有某种Sleep语句 PS:我问这个问题是因为问题的一个评论。在那里,OP指出,在他看来,睡眠是要避免的,就像在现实世界中,使用适当的同步原语并不总是切实可行的: 有时您需要轮询某些内容,直到满足某个条件,然后使用sleep来避免浸泡机器 有时,您主动地想

首先,在许多情况下,
Sleep()
误用,例如“同步”线程或定期轮询通知函数将执行的值(例如在Win32
WaitForSingleObject
中)

但是其他用例呢睡眠总是有害的吗?如果不是,那么睡眠的好用例是什么?如果是,为什么几乎所有语言都有某种
Sleep
语句


PS:我问这个问题是因为问题的一个评论。在那里,OP指出,在他看来,
睡眠
是要避免的,就像在现实世界中,使用适当的同步原语并不总是切实可行的:

  • 有时您需要轮询某些内容,直到满足某个条件,然后使用
    sleep
    来避免浸泡机器

  • 有时,您主动地想要睡眠—例如,当您希望线程占用最少的机器资源,而您所使用的操作系统(cough Windows cough)在防止低优先级线程浸泡机器方面做得不好时


编辑回应基维利的评论:我认为你应该在可能的时候实施适当的信号传递。因此,工作线程应该对队列执行阻塞读取,而不是休眠和轮询。我是说,有时候你不得不与那些妨碍你做正确事情的系统进行交互。我并不是说你不应该在合理可能的情况下做正确的事情——“半秒钟内就足够了”,也许,但近瞬间会明显更好

IMHO只有在编写良好的操作系统并且在操作系统的正常范围内工作时,才能避免sleep()

当您必须在操作系统(如嵌入式软件/固件)之外和正常领域(如驱动程序)之外工作时,您将无法使用线程技术,因为没有任何东西可以为您切换任务。因此,你别无选择,只能做旋转锁和轮询等待之类的事情,因为没有先发制人来帮助你


此外,如果您正在针对非基于事件的API进行集成,那么您有时别无选择,只能轮询信息,因此在这种情况下,您最好的选择是至少休眠,而不是自旋锁,以便让操作系统在您等待时做些事情。

实现
tail-f
需要
休眠()。i、 e.
stat()
如果文件已更改,请读入差异,然后
sleep()
一段时间……继续,直到中断

< P> >我认为这是一个有效的使用<代码>睡眠()/代码>

作为Linux上的一个例子,
strace-tail-f foo
,可以归结为

clock_gettime(CLOCK_REALTIME, {1247041913, 292329000}) = 0
nanosleep({1, 0}, NULL)                 = 0
fstat64(3, {st_mode=S_IFREG|0755, st_size=357, ...}) = 0
clock_gettime(CLOCK_REALTIME, {1247041914, 311933000}) = 0
nanosleep({1, 0}, NULL)                 = 0
fstat64(3, {st_mode=S_IFREG|0755, st_size=357, ...}) = 0
clock_gettime(CLOCK_REALTIME, {1247041915, 355364000}) = 0
....
read(0, 0x00024718, 65537)                      = 0
nanosleep(0xFFBFF1A0, 0xFFBFF198)               = 0
read(0, 0x00024718, 65537)                      = 0
nanosleep(0xFFBFF1A0, 0xFFBFF198) (sleeping...)
nanosleep(0xFFBFF1A0, 0xFFBFF198)               = 0
read(0, 0x00024718, 65537)                      = 0
好的,这是
nanosleep()
,但同样的规则适用

Solaris
truss tail-f foo

clock_gettime(CLOCK_REALTIME, {1247041913, 292329000}) = 0
nanosleep({1, 0}, NULL)                 = 0
fstat64(3, {st_mode=S_IFREG|0755, st_size=357, ...}) = 0
clock_gettime(CLOCK_REALTIME, {1247041914, 311933000}) = 0
nanosleep({1, 0}, NULL)                 = 0
fstat64(3, {st_mode=S_IFREG|0755, st_size=357, ...}) = 0
clock_gettime(CLOCK_REALTIME, {1247041915, 355364000}) = 0
....
read(0, 0x00024718, 65537)                      = 0
nanosleep(0xFFBFF1A0, 0xFFBFF198)               = 0
read(0, 0x00024718, 65537)                      = 0
nanosleep(0xFFBFF1A0, 0xFFBFF198) (sleeping...)
nanosleep(0xFFBFF1A0, 0xFFBFF198)               = 0
read(0, 0x00024718, 65537)                      = 0
如果您使用Sleep()处理的案例不仅仅涉及正在运行的线程,那么很可能是您做错了什么


也就是说,有时你想暂停处理,例如在一个无休止的(或实际上是如此)工作循环中,给其他进程一些喘息的空间。

如果睡眠被用于“忙碌的等待”,它就会被误用。然而,在某些情况下,使用睡眠
在旋转锁中或当您没有允许您使用不同事件源的API时。

有时,您不希望不断刷新显示,例如在系统或网络监视器中。另一个例子是watch(1)——在没有睡眠的情况下如何实现它?

我发现使用
Thread.sleep(1000)很有用
模拟在web应用程序中编写回调时的延迟

微软AJAX组件的一个简单示例是在更新面板中放置一个按钮。。。在onclick处理程序use Thread.Sleep()上,更新进度面板将显示该时间段


在上线时,请删除线程。Sleep():)

我最常用的
Sleep
是说明多线程代码中的问题,但除此之外,还有一些其他答案中提到的有效用法。

都是关于如何使用它的

在我们在工作中使用的一些代码中,一位开发人员将睡眠时间(5)设为5毫秒,并注释“睡眠使我的电脑仍然可用”,这很好,但我们的客户抱怨速度性能的情况除外。所以我删除了它,吞吐量翻了一番,但他把它放回sleep(0),抱怨他的机器在进行大数据加载测试时没有响应。呻吟,买一台新的开发电脑

正如我所说,没有问题的是,您确实不希望加载系统睡眠,或者将睡眠与轮询类型操作结合使用。

在Java和.Net中,sleep()是可中断的

因此,如果您使用sleep(),并且另一个线程在需要时中断您(导致抛出InterruptedException),那么这没有什么错

我目前正在通过一些外部队列编写轮询机制,我的代码基本上是:

while (true)
{
  items = takeFromQueue();
  if (items.size() == 0)
    sleep(1000);
}

另一个线程可以通过调用thread.interrupt()安全地停止这个线程

我实际上相信你链接的断言是正确的。问题是睡眠被用作通知机制的低效替代品(正如您所指出的)。如果您正在等待事件,则睡眠总是不如正确实现的通知机制。如果你真的需要等待一段时间,那么睡觉是合适的

例如,在某些网络协议中,您使用了一种称为指数退避的技术,如果您在网络上检测到冲突,您希望在重试之前等待一段随机(且指数增加)的时间。在这种情况下,睡眠是合适的,因为你不是在试图等待事件发生,而是在尝试不去做