轮询本身并没有错。
很大程度上取决于它的实现方式和目的。如果你真的关心对更改的立即通知,那么它非常有效。你的代码处于紧密循环中,不断轮询(询问)一个资源是否已更改/更新。这意味着你会在可以的最早时间收到通知有些东西发生了变化。但是,你的代码除此之外什么也不做,而且存在大量对对象的调用开销。
如果你对立即通知不太关心,可以增加轮询之间的间隔,这也可以很好地工作,但是选择正确的间隔可能很困难。间隔时间太长,你可能会错过关键的更改,间隔时间太短,你就会回到第一种方法的问题。
替代方案,如中断或消息等,在这些情况下提供更好的折衷方案。你会尽快收到有关更改的通知,但这种延迟不是由你控制的,而是取决于组件本身及时地传递状态更改。
轮询的问题是什么?
但是...
以下是现今一些使用轮询的例子:
有时候根本没有办法获取异步通知: 例如,要使用推送系统替换 RSS,服务器必须知道所有阅读该订阅源的人,并且有一种联系他们的方法。而这就是邮件列表——这正是 RSS 设计的目的之一。因此,我的大部分例子都是网络应用程序,在这种情况下,这最有可能是一个问题。
在其他时候,轮询足够便宜,可以在异步通知存在的情况下工作。
对于本地文件,原则上通知更改可能是更好的选择。例如,如果你不断地读取它,你可能(可能)会防止磁盘停转,尽管操作系统可能会缓存。如果你每秒钟轮询一个仅每小时更改一次的文件,你可能会不必要地占用计算机处理能力的 0.001%(或任何百分比)。这听起来很小,但当你需要轮询100,000个文件时会怎么样呢?
然而,在实践中,无论你选择哪种方式,开销都可能是微不足道的,这使得难以对当前正常运行的代码进行更改。最好的方法是注意想要更改的系统上轮询引起的具体问题——如果你发现了任何问题,则提出这些问题,而不是试图针对所有轮询进行一般性论证。如果没有发现任何问题,那就不要去修复已经正常的东西了...
轮询存在两个原则上的不足之处:
它是一种资源浪费。你很有可能会在没有任何变化发生的情况下检查变化。在这种行为中花费的 CPU 循环/带宽并没有产生变化,因此本可以用于其他更加有用的方面。
轮询是在一定的时间间隔内进行的。这意味着直到下次间隔到来之前,您不会知道是否发生了变化。
最好的方式是通过通知来获得变化的信息。这样,您就不必对未发生变化的情况进行轮询,并且在收到通知时就立即知道了变化。
轮询很容易做,非常简单,就像任何过程化代码一样容易。不使用轮询意味着你进入了异步编程的世界,这并不像大脑死亡般容易,有时甚至会变得具有挑战性。
而作为任何系统中的一切事物一样,通常选择路径最小阻力,所以总会有程序员使用轮询,即使是优秀的程序员,因为有时候没有必要用异步模式复杂化事情。
我个人总是努力避免使用轮询,但有时我仍然会使用轮询,特别是当异步处理的实际收益并不那么大时,如在某些小型本地数据上操作(当然你会更快一些,但用户在这种情况下不会注意到差异)。所以,在我的看法中,两种方法都有其应用场景。
客户端轮询不如服务器通知具有良好的扩展性。想象成千上万的客户端每5秒钟向服务器询问“是否有新数据?”。现在想象一下,服务器维护一个客户端列表以通知新数据。服务器通知具有更好的可扩展性。
我认为人们应该意识到,在大多数情况下,即使在事件或中断驱动的情况下,也会进行一定程度的轮询,但是您与实际执行轮询的代码是隔离的。实际上,这是最理想的情况...将自己与实现隔离开来,只处理事件。即使您必须自己实现轮询,也要编写代码,使其隔离,并且结果独立于实现进行处理。
很简单 - 轮询是不好的 - 低效、浪费资源等等。即使没有选择“轮询”,总会有某种形式的连接在监视某种事件。
那么为什么还要额外添加轮询呢?
回调是最好的选择 - 只需要担心将回调与当前进程联系起来即可。在底层,仍然会进行轮询以查看连接是否仍然存在。
如果你一直打电话/打给你的女朋友,她从不回答,那么为什么还要继续打电话呢?只需留言,等待她“回电”即可;)
我偶尔会在某些情况下使用轮询(例如,在游戏中,我会每帧轮询键盘状态),但从不在仅进行轮询的循环中使用它,而是将轮询作为检查的一部分(资源X是否发生了变化?如果是,执行某些操作,否则处理其他事情并稍后再次检查)。总体来说,我更喜欢异步通知,而避免使用轮询的原因是我不想浪费资源(CPU时间等)等待某些事情的发生(特别是如果这些资源可以加速该事情的发生)。在我使用轮询的情况下,我不会闲置等待,我会将资源用于其他方面,所以这对我来说不是问题。