当事件模式不适用时,线程应该休眠多久?

4
在必须轮询以了解是否有工作要做的工作线程的主循环中,我让它睡眠以避免繁忙等待。我如何确定适当的睡眠时间?例如,如果我每毫秒醒来一次,可能根本没有必要睡觉。如果我每十分钟醒来一次,这可能会使应用程序看起来不响应(取决于线程正在执行什么操作)。
我之前听说过Cadrian所说的,即人类用户不会注意到100毫秒左右的时间跨度,但是从机器方面接近它呢?间隔可以变得多小,才开始变得浪费?
我想,这归结为一个更一般(即与平台无关)的版本this question
编辑:当然,问题应始终首先重新表述为“如何将其更改为事件模式而不是轮询”,但现在先假设我不能或不想这样做。

你自相矛盾。你说你在等待输入,然后又说你不能阻塞直到事件发生 - 输入本身就是一个事件的发生。 - Paul Tomblin
是的,那确实是对的。我会澄清一下。 - Hanno Fietz
澄清了那一点,谢谢。 - Hanno Fietz
5个回答

7

有时候轮询确实是答案

然而,它轮询的频率取决于线程正在做什么,因此要使其可配置。

我们有检查电子邮件的线程。它们可以检查外部邮箱,但我们只会每隔三十秒检查一次(但这是可配置的)。每个检查都是通过网络调用完成的,每秒或每十分之一秒调用一次会对网络造成压力,30秒则可以,即使电子邮件在收件箱中落地时未被处理,也没有关系(但某些客户网站每5分钟检查一次)。

我们有其他线程,用于轮询文件夹中的文件和/或数据库表中添加的新请求。这些线程每1到5秒轮询一次(取决于它们正在做什么)。

现在无论你在轮询之间等待多长时间,我们都不会让任何线程睡眠超过一秒钟。原因是,如果您尝试停止具有睡眠60秒线程的Windows服务,则可能需要等待60秒才能停止服务。

如果您需要快速关闭计算机,Rip Van Winkle线程将真正扭曲您的大脑。

所以,将轮询间隔设置得尽可能远,但不要睡眠时间超过一秒钟。

希望这能帮到您


谢谢,你提供的例子非常有用。 - Hanno Fietz
1
还有一个很好的观点是轮询和睡眠是两个不同的事情,可能需要不同的间隔时间。我没有考虑过关机,而这在我的应用程序中实际上非常重要。 - Hanno Fietz

2
你知道这个操作大概需要多长时间吗?也许是一个范围?我假设你的线程基本上是这样实现的:
while(!workComplete) {
  Thread.Sleep(n);
}

如果这是一个UI工作线程,只要它们有某种形式的进度指示器,最多半秒钟应该就足够了。由于这是一个后台线程,并且肯定有足够的CPU时间可用于每500毫秒检查一次,所以UI在操作期间应该保持响应。当然,这取决于您的UI需要多少响应能力,但请记住,在涉及UI时,一切都是关于感知性能的。
另一种方法是指数回退。假设您在200毫秒后检查输入是否已完成。如果没有完成,则下一次休眠400毫秒。如果之后它仍未完成,则休眠800毫秒等等。您应该确保在一段时间后抛出TimeoutException,以便避免一些长时间的休眠。

如果您要点踩,请留言评论。我很乐意听听在提问者所询问的内容方面,这个答案哪里出了问题。 - Szymon Rozga
我认为这完全没有错。但是我已经点赞了,所以无论如何我也解释不了。 - Hanno Fietz

1
如果同一应用程序的另一个线程给你的线程提供数据,那么你应该考虑使用事件模式而不是轮询。例如,在Java中,你可以使用wait/notify。
否则,如果应用程序面向用户,每100毫秒进行一次轮询应该足够了。用户不会注意到。

0

你应该发出一个信号来提醒线程。如果你正在使用C语言,可以使用p-threads中的条件变量。如果你正在使用像.NET这样的较新技术,可以使用EventWaitHandle。我相信Java和其他4GL语言也有类似于EventWaitHandle的类。


即使在第一次修订中,我已经排除了基于事件的唤醒,但可能并不够清楚。我现在已经澄清了这篇文章。 - Hanno Fietz

-1

让它永远睡眠,当有输入可用时再唤醒它?


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