睡觉()邪恶吗?

Dan*_*ski 40 language-agnostic

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

但是其他用例呢?Sleep始终邪?如果没有,有什么好的用例Sleep?如果是的话,为什么几乎所有语言都有某种Sleep陈述?

PS:我问过这个问题是因为另一个问题的评论之一.OP表示,在他看来,Sleep应该避免像goto.

Fal*_*ina 40

我实际上相信你联系的断言是正确的.问题是正在使用睡眠(如您所述)作为通知机制的低效替代品.如果您正在等待事件,则睡眠总是不如正确实施的通知机制.如果您确实需要等待特定时间的某些事情,那么睡眠是合适的.

例如,在某些网络协议中,您使用称为指数退避的技术,如果您在网络上检测到冲突,则需要在重试之前等待一段随机(并且指数增加)的时间.在这种情况下,睡眠是合适的,因为你不是要等待事件发生,你正试图等待一段特定的时间来通过.


小智 20

Thread.Sleep(1000);在Web应用程序中编写回调时,我发现用于模拟延迟很有用.

使用Microsoft的AJAX组件的一个简单示例是在更新面板中放置一个按钮... onclick处理程序使用Thread.Sleep(),然后更新进度面板将显示该时间量.

上线时显然删除Thread.Sleep()... :)

  • 是的,完全同意.有时AJAX功能处理过快,提供等待是很好的.这会在屏幕上以等待图像(或者您正在使用的任何形式)的形式向用户提供视觉反馈,以便他们知道某些内容正在发生变化/已经发生变化. (2认同)
  • 是的,特别是在开发环境中,很可能在你的本地机器上回调很快,Sleep()让你有机会看到你的漂亮加载图形,确保它的一切正确等:) (2认同)

Ric*_*dle 19

在现实世界中,使用适当的同步原语并不总是可行的:

  • 有时你需要轮询一些东西,直到满足条件,并且你用它sleep来避免浸泡机器.

  • 有时你会主动想要睡觉 - 例如,当你想要一个线程占用最少的机器资源而你正在操作系统(咳嗽 Windows 咳嗽)时,它不能很好地防止低优先级线程浸泡机器.

编辑以回应Kieveli的评论:我认为你应该尽可能地实施适当的信号.因此,工作线程应该对队列执行阻塞读取而不是休眠和轮询.我说有时你被迫与那些排除做正确事情的系统互动.我并不是说你不应该在合理可能的情况下做正确的事情 - "半秒钟就足够了",也许,但是接近瞬时会明显好转!


Ste*_*sop 8

与所有其他"是邪恶的"问题一样的答案.

这是一个低级别的操作.人们有时会使用低级操作来重新发明已经作为高级操作使用的轮子.这是不明智的,你应该确保它不是你正在做的.但是如果你实际上是在低级编程,那么你可能会使用低级操作.一些高级程序员会认为你是邪恶的或愚蠢的或两者兼而有之.你知道的更好,因为你是编写高级平台的人,他们可以自己闭嘴或者自己动手.

考虑到使用高级构造的邪恶扭曲和使用低级构造的邪恶扭曲之间的选择,有些人认为你应该总是喜欢前者.我并没有真正得到他们的POV,但他们至少是一致的,所以你不能责怪他们,除非后者明显更快/更小/更好.

睡眠的好用途:

  • 当你必须阻止到一定时间(或一段时间).您的语言/库/操作系统可能提供也可能不提供阻止计时器来完成工作.如果没有,那么睡眠是永远可用的选择.如果是这样的话,它可能会完全与沼泽标准的睡眠循环完成相同的事情,所以请使用更少的代码.

  • 实现其他原语时,如计时器.

  • 当您在POSIX或其他任何地方使用信号进行异步线程间或进程间消息传递时.你只是一直睡觉,信号处理人员要么工作,要么设置状态告诉你需要做什么工作,你醒来时就做.当然你可以使用其他的API,但除非你主动更喜欢那个API,否则你只是避免睡觉,因为互联网上的一些家伙告诉你.也许当他编写一种没有睡眠的编程语言,并且比你当前的语言更好时,你就会转向那种语言.

睡眠的主要问题(除了线程之间并没有真正做很多交互,因此通常是需要这些工作的错误工具)就是即使你没有消耗任何CPU时间,你仍然在消耗资源因为你有一个坐在无所事事的线程.根据平台,线程可能很昂贵.在单核系统上,两个的第二个线程特别昂贵,因为如果你可以摆脱它,你的大多数数据同步问题就会消失.因此,如果您可以合理地设计您的应用程序,使其永远不需要多个线程,并且永远不会阻塞,除非在某些事件循环中,因为一切都是通过异步消息完成的,然后这样做,您将不需要睡眠.


Bea*_*ano 7

实施tail -f将需要一个sleep().即stat()文件,如果它已经改变,读入差异,然后sleep()一点......继续直到中断.

我认为这是一个有效的用途 sleep()

作为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
....
Run Code Online (Sandbox Code Playgroud)

好的,nanosleep()但是适用相同的规则.

Solaris truss tail -f foo安顿下来

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
Run Code Online (Sandbox Code Playgroud)

  • 事实上,大多数现代操作系统都有某种文件更改通知机制,即"如果此文件发生更改,请将其唤醒".Linux已经通知了,在Windows下有ChangeNotification等.所以通常不鼓励轮询文件.可能会像tail -f那样矫枉过正... (6认同)

Rôm*_*con 5

除了Chalkey提到的测试目的之外,我发现我从来不需要在Linux,Windows和OS/X等高级操作系统上调用sleep.即使在程序预期只是等待一段时间的情况下,我在信号量上使用等待函数并且超时,这样我可以通过释放信号量立即结束线程,如果某事/某人要求我的程序终止:

# [pseudo-code]

if wait_semaphore(exit_signal_semaphore, time_to_sleep)
  # another thread has requested this one to terminate
  end_this_thread
else
  # event timed-out; wait_semaphore behaved like a sleep function
  do_some_task
end
Run Code Online (Sandbox Code Playgroud)


Pas*_*nen 5

我在这里看不到它,但sleep()是一个非常肯定的方法,可以让你的CPU时间片更有价值.当你睡眠()时,操作系统会控制并决定下一个应该运行的人,这也允许来自同一进程的其他线程有CPU时间.当生成多个线程并且Controller等待Workers准备就绪时,这可以减轻单CPU机器上的CPU压力.