System.Threading.Timer的可伸缩性如何?

时间:2020-03-05 18:44:13  来源:igfitidea点击:

我正在编写一个需要使用Timers的应用程序,但其中可能有很多。 System.Threading.Timer类的可伸缩性如何?该文档仅说它是"轻量级的",而没有进一步解释。这些计时器是否陷入代表一个"计时器"处理所有回调的单个线程(或者很小的线程池)中,或者每个"计时器"都有自己的线程?

我猜想重新表达这个问题的另一种方法是:如何实现System.Threading.Timer?

解决方案

回答

我认为我们可能想重新考虑设计(也就是说,如果我们自己可以控制设计)。如果我们使用了太多计时器,实际上这是我们所关心的,那么那里显然存在合并的潜力。

这是几年前《 MSDN杂志》上的一篇好文章,比较了三个可用的计时器类,并对它们的实现提供了一些见解:

http://msdn.microsoft.com/zh-CN/magazine/cc164015.aspx

回答

我说这是为了回答许多问题:不要忘记该框架的(托管)源代码可用。我们可以使用此工具来获取全部信息:http://www.codeplex.com/NetMassDownloader

不幸的是,在这种特定情况下,很多实现都是在本机代码中进行的,因此我们不必去看它……

但是,他们肯定使用池线程,而不是按计时器线程。

实现大量计时器的标准方法(这是内核在内部进行操作的方式,我可能会间接怀疑大量计时器是如何结束的)是维护按时间到到期时间排序的列表,因此系统只需担心检查即将到期的下一个计时器,而不用担心整个列表。

粗略地讲,这为启动计时器提供了O(log n),为运行计时器提供了O(1)。

编辑:一直在寻找杰夫·里希特(Jeff Richter)的书。他说(对于Threading.Timer),它对所有Timer对象都使用一个线程,该线程知道下一个计时器(即如上所述)的到期时间,并在适当的时候调用ThreadPool.QueueUserWorkItem进行回调。这样的结果是,如果我们没有在计时器上完成对某个回调的服务,而后一个计时器到期,那么回调将在另一个池线程上重新输入。因此,总而言之,我怀疑我们会发现拥有大量计时器会遇到很大的问题,但是如果大量计时器在同一计时器处触发和/或者它们的回调运行缓慢,则可能会导致线程池耗尽。

回答

就像DannySmurf所说的:^巩固它们。创建一个计时器服务,并要求提供计时器。它只需要保留1个活动计时器(用于下一个到期调用)和所有计时器请求的历史记录,然后在AddTimer()/ RemoveTimer()上重新计算该时间即可。

回答

Consolidate them. Create a timer
  service and ask that for the timers.
  It will only need to keep 1 active
  timer (for the next due call)...

为了使它比仅创建许多Threading.Timer对象更好,我们必须假定它与Threading.Timer在内部已经不完全一样。我很想知道我们是如何得出这个结论的(我还没有分解框架的本机部分,所以我们很可能是正确的)。