我正在编写一个需要使用Timer
s 的应用程序,但可能很多。课程的可扩展性如何System.Threading.Timer
?文档只是说它是“轻量级的”,但没有进一步解释。这些计时器是否被吸入代表 a 处理所有回调的单个线程(或非常小的线程池)中Timer
,还是每个Timer
都有自己的线程?
我想另一种表述问题的方式是:如何System.Threading.Timer
实施?
我正在编写一个需要使用Timer
s 的应用程序,但可能很多。课程的可扩展性如何System.Threading.Timer
?文档只是说它是“轻量级的”,但没有进一步解释。这些计时器是否被吸入代表 a 处理所有回调的单个线程(或非常小的线程池)中Timer
,还是每个Timer
都有自己的线程?
我想另一种表述问题的方式是:如何System.Threading.Timer
实施?
我这样说是为了回答很多问题:不要忘记框架的(托管)源代码是可用的。您可以使用此工具获取所有内容:http: //www.codeplex.com/NetMassDownloader
不幸的是,在这种特定情况下,很多实现都是在本机代码中,所以你看不到它......
不过,他们肯定使用池线程而不是每个计时器线程。
实现大量计时器的标准方法(这是内核在内部执行它的方式,我怀疑间接地是您的大型计时器集合如何结束)是维护按时间到到期排序的列表 - 所以系统只需要担心检查即将到期的下一个计时器,而不是整个列表。
粗略地说,这给了 O(log n) 用于启动计时器和 O(1) 用于处理正在运行的计时器。
编辑:刚刚在看 Jeff Richter 的书。他说(关于 Threading.Timer)它对所有 Timer 对象使用单个线程,该线程知道下一个计时器(即如上所述)何时到期,并酌情调用 ThreadPool.QueueUserWorkItem 进行回调。这样做的效果是,如果您没有在下一个回调到期之前完成对计时器的一个回调的服务,那么您的回调将重新进入另一个池线程。所以总而言之,我怀疑你会看到拥有大量计时器的大问题,但如果大量计时器在同一个计时器上触发和/或它们的回调运行缓慢,你可能会遭受线程池耗尽。
我认为您可能需要重新考虑您的设计(也就是说,如果您自己可以控制设计)。如果您使用的计时器太多以至于这实际上对您来说是一个问题,那么显然有一些整合的潜力。
这是几年前来自 MSDN 杂志的一篇好文章,它比较了三个可用的计时器类,并对它们的实现提供了一些见解:
巩固他们。创建一个计时器服务并询问计时器。它只需要保持 1 个活动计时器(用于下一次到期呼叫)......
要使这比仅创建大量 Threading.Timer 对象有所改进,您必须假设这并不是 Threading.Timer 内部已经在做的事情。我很想知道你是如何得出这个结论的(我没有分解框架的原生部分,所以你很可能是对的)。
^^ 正如 DannySmurf 所说:合并它们。创建一个计时器服务并询问计时器。它只需要保留 1 个活动计时器(用于下一次到期调用)和所有计时器请求的历史记录,并在 AddTimer() / RemoveTimer() 上重新计算。