轮询有什么问题?

40

最近我听到一些开发人员说,他们只是轮询数据库、文件等来确定何时发生了更改,然后运行任务(例如导入)。

我非常反对这种想法,认为利用可用技术例如远程调用WCF等比轮询更好。

然而,我想找出其他人喜欢一种方法胜过另一种的原因,更重要的是,如何说服其他人在现代社会中放弃轮询的方式?


FYI:Remoting和WCF进行轮询。 - Timothy Khouri
在某种程度上是的,但不是像一些开发人员明确使用轮询的方式,即每分钟轮询一次数据库。 - HAdes
我有一个类似的情况,需要在多个ftp位置上进行多次轮询以获取更新的文件,应该采取什么最优方式来处理这种情况? - Rachel
除了“因为它更容易”,另一个常见的需要进行轮询的原因是被轮询的对象无法更改为推送通知(可能是因为它不在您的控制范围内;更改它的成本或风险被认为太高等)。 - TripeHound
我完全同意你的观点,这是错误的,它毫无意义地占用了资源。人们这样做的原因是因为这是最简单的选择。 - MarcusJ
18个回答

47

轮询本身并没有错。

很大程度上取决于它的实现方式和目的。如果你真的关心对更改的立即通知,那么它非常有效。你的代码处于紧密循环中,不断轮询(询问)一个资源是否已更改/更新。这意味着你会在可以的最早时间收到通知有些东西发生了变化。但是,你的代码除此之外什么也不做,而且存在大量对对象的调用开销。

如果你对立即通知不太关心,可以增加轮询之间的间隔,这也可以很好地工作,但是选择正确的间隔可能很困难。间隔时间太长,你可能会错过关键的更改,间隔时间太短,你就会回到第一种方法的问题。

替代方案,如中断或消息等,在这些情况下提供更好的折衷方案。你会尽快收到有关更改的通知,但这种延迟不是由你控制的,而是取决于组件本身及时地传递状态更改。

轮询的问题是什么?

  • 它可能会占用资源。
  • 它可能会具有限制性(特别是如果你想了解/轮询的东西有很多)。
  • 它可能会过度使用。

但是...

  • 轮询本身并没有错。
  • 它可以非常有效。
  • 它非常简单。

2
这意味着尽可能快地通知您有什么不同。这不是取决于轮询间隔和您与事件发生时间的接近程度吗? - Svish
8
在某些情况下,轮询比使用消息更有效。这取决于“事件”的数量和频率。举一个有点牵强的例子,考虑一个每秒测量温度100次并发送更新的温度计。如果您为每个更新使用单独的消息,则需要处理每秒100个消息。但是假设您只关心每5秒测量一次温度。在这种情况下,每5秒轮询一次将比处理500条消息更有效。 - Gregory Mostizky

28

以下是现今一些使用轮询的例子:

  • 电子邮件客户端会轮询新消息(即使使用IMAP)。
  • RSS 阅读器会轮询订阅源的更改。
  • 搜索引擎会轮询索引页面的更改。
  • StackOverflow 用户通过点击“刷新”来轮询新问题;-)
  • Bittorrent 客户端会轮询跟踪器(我认为还有彼此之间使用DHT),以了解群集中的更改。
  • 在多核系统上,自旋锁可能是最有效的核间同步方式,在这种情况下,延迟太短,无法在其他核心执行我们等待的操作之前在该核心上安排另一个线程。

有时候根本没有办法获取异步通知: 例如,要使用推送系统替换 RSS,服务器必须知道所有阅读该订阅源的人,并且有一种联系他们的方法。而这就是邮件列表——这正是 RSS 设计的目的之一。因此,我的大部分例子都是网络应用程序,在这种情况下,这最有可能是一个问题。

在其他时候,轮询足够便宜,可以在异步通知存在的情况下工作。

对于本地文件,原则上通知更改可能是更好的选择。例如,如果你不断地读取它,你可能(可能)会防止磁盘停转,尽管操作系统可能会缓存。如果你每秒钟轮询一个仅每小时更改一次的文件,你可能会不必要地占用计算机处理能力的 0.001%(或任何百分比)。这听起来很小,但当你需要轮询100,000个文件时会怎么样呢?

然而,在实践中,无论你选择哪种方式,开销都可能是微不足道的,这使得难以对当前正常运行的代码进行更改。最好的方法是注意想要更改的系统上轮询引起的具体问题——如果你发现了任何问题,则提出这些问题,而不是试图针对所有轮询进行一般性论证。如果没有发现任何问题,那就不要去修复已经正常的东西了...


5
哦我的天!我是一个投票设备。:O - EMBarbosa

25

轮询存在两个原则上的不足之处:

  1. 它是一种资源浪费。你很有可能会在没有任何变化发生的情况下检查变化。在这种行为中花费的 CPU 循环/带宽并没有产生变化,因此本可以用于其他更加有用的方面。

  2. 轮询是在一定的时间间隔内进行的。这意味着直到下次间隔到来之前,您不会知道是否发生了变化。

最好的方式是通过通知来获得变化的信息。这样,您就不必对未发生变化的情况进行轮询,并且在收到通知时就立即知道了变化。


2
请注意,有时轮询可以节省资源。它设置了执行繁重任务的频率上限,即轮询间隔。虽然并不经常相关,但当它相关时可能非常重要。 - Steve Jessop
6
当然,提供变更通知的大多数事物本身都是在轮询以侦测变化。在许多情况下,轮询先于变更通知。 - Jeff Yates

23

轮询很容易做,非常简单,就像任何过程化代码一样容易。不使用轮询意味着你进入了异步编程的世界,这并不像大脑死亡般容易,有时甚至会变得具有挑战性。

而作为任何系统中的一切事物一样,通常选择路径最小阻力,所以总会有程序员使用轮询,即使是优秀的程序员,因为有时候没有必要用异步模式复杂化事情。

我个人总是努力避免使用轮询,但有时我仍然会使用轮询,特别是当异步处理的实际收益并不那么大时,如在某些小型本地数据上操作(当然你会更快一些,但用户在这种情况下不会注意到差异)。所以,在我的看法中,两种方法都有其应用场景。


8
+1赞同常识:“有时候没有必要用异步模式来复杂化事情。” - JeffK

8

客户端轮询不如服务器通知具有良好的扩展性。想象成千上万的客户端每5秒钟向服务器询问“是否有新数据?”。现在想象一下,服务器维护一个客户端列表以通知新数据。服务器通知具有更好的可扩展性。


1
非常好的观点,我发现现代程序员在处理处理器、空间和带宽问题时往往比较懒惰,因为他们有这种有趣的想法,认为这些东西会无限地改进,但最终我们将达到不可能再改进这些东西的地步。异步通知并不像人们所说的那样可怕,任何在现代操作系统上编写GUI的程序员都经常处理异步通知。 - user109878

5

我认为人们应该意识到,在大多数情况下,即使在事件或中断驱动的情况下,也会进行一定程度的轮询,但是您与实际执行轮询的代码是隔离的。实际上,这是最理想的情况...将自己与实现隔离开来,只处理事件。即使您必须自己实现轮询,也要编写代码,使其隔离,并且结果独立于实现进行处理。


这并不总是准确的。在对象属性发生变化的情况下,对象本身可以设置一个通知,当属性被设置时会触发该通知。在这种情况下,轮询不一定会发生,尽管在对象实际检查旧值和新值之间的差异时,它肯定可以发生。 - user109878

3
关于轮询的事情是它是可靠的,而且实现起来很简单。
轮询的成本可能很高——如果您每分钟扫描一次数据库以查找仅有两个更改的情况,则会为非常小的结果消耗大量资源。
然而,任何通知技术的问题在于它们要实现的复杂性,不仅可能不可靠,而且(这是一个大问题)当它们不工作时,您不能轻易地告诉它们不工作。
因此,如果您使用其他技术替换轮询,请确保它对普通程序员可用并且超级可靠。

我同意你的观点,在我的当前应用程序中,我正在执行相同的轮询机制并检查文件更新,但这非常耗费资源并且占用了大量资源,有什么最佳的优化方法来处理这种情况? - Rachel

3

很简单 - 轮询是不好的 - 低效、浪费资源等等。即使没有选择“轮询”,总会有某种形式的连接在监视某种事件。

那么为什么还要额外添加轮询呢?

回调是最好的选择 - 只需要担心将回调与当前进程联系起来即可。在底层,仍然会进行轮询以查看连接是否仍然存在。

如果你一直打电话/打给你的女朋友,她从不回答,那么为什么还要继续打电话呢?只需留言,等待她“回电”即可;)


你可以设置控制来确保远程对象始终处于有效状态,或报告无法自行解决的问题。或者继续这个比喻,让答录机持续哔哔声,以便女朋友立即注意到它,或发送一条短信警告其他人她可能有麻烦。 - HAdes

3

我偶尔会在某些情况下使用轮询(例如,在游戏中,我会每帧轮询键盘状态),但从不在仅进行轮询的循环中使用它,而是将轮询作为检查的一部分(资源X是否发生了变化?如果是,执行某些操作,否则处理其他事情并稍后再次检查)。总体来说,我更喜欢异步通知,而避免使用轮询的原因是我不想浪费资源(CPU时间等)等待某些事情的发生(特别是如果这些资源可以加速该事情的发生)。在我使用轮询的情况下,我不会闲置等待,我会将资源用于其他方面,所以这对我来说不是问题。


2
如果您正在轮询文件的更改,那么我认为您应该使用操作系统中可用的文件系统通知来进行此操作,这在大多数操作系统中都是可用的。
在数据库中,您可以在更新/插入时触发并调用外部代码执行某些操作。但是,也许您并没有立即执行操作的要求。例如,您可能仅需要在15分钟内从数据库A获取数据并传输到不同网络中的数据库B。数据库B可能无法从数据库A访问,因此您必须从或作为独立运行程序轮询Database B。
此外,轮询是一种非常简单的编程方法。它通常是在时间限制紧迫时进行的第一步实施,因为它足够有效,所以它保持不变。

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