如何有效地实现大量的定时器?

时间:2014-06-02 06:44:06

标签: c++ timer boost-asio

我用C ++编写的程序可能有数十万个对象,每个对象都有一个到期时间,如果在一段时间内处于非活动状态,它们应被删除。许多对象经常变得活跃,并且新对象的创建也非常迅速。

我对使用什么方法犹豫不决。我一直在阅读Asio计时器,但我不太确定他们是否能很好地满足我的需求,如果他们这样做的话,我也不知道如何。我有两种方法:

  1. 我可以为每个对象创建一个死区计时器,并在对象执行某些操作时重置它。这意味着我将拥有数十万计时器。

  2. 我可以制作多个计时器队列,例如30个计时器,30秒到期时间。第一个计时器用于剩余30秒生命周期的对象。如果它们处于非活动状态一秒钟,它们将被移动到计时器队列中,以获得具有29秒生命周期的对象。如果一秒钟处于非活动状态,则删除最后一个队列中的对象。任何变为活动的对象都会返回到第一个队列。

  3. 第二种方法听起来效率更高,但它真的吗?如果Asio可以有效地处理大量的定时器,那么第二种方法可能会浪费我很多努力。我该怎么做?或者有更好的方法吗?

    编辑:我想我必须通过效率添加它意味着更好的CPU利用率。内存使用是这里的次要问题。

4 个答案:

答案 0 :(得分:2)

我会创建一个队列,根据剩余的剩余时间对对象进行排序。如果期望过期时间频繁,我会使用链表,否则就是数组,因为在列表中找到一些东西会更快(但是如果你在对象本身中保留对下一个和前一个对象的引用而不是节点,没关系)。

  • 现在,您只需要单个计时器来处理具有最短到期时间的对象。
  • 当此计时器用完时,删除队列开头的对象并为下一个计时器准备计时器。

答案 1 :(得分:1)

制作数字的plist并给出timer的逻辑。这是实现定时器的最有效方法,因为它消耗更少的内存。

答案 2 :(得分:0)

我会选择第一种方法,但是当您尝试执行操作并且截止日期已过期时,仅删除对象。实现起来要容易得多,因为它是 lazy ,因为你不必评估计时器(意味着当你尝试使用该对象时)。

如果考虑效率,无论何时进行,删除对象的工作都应该相同。

保持截止时间的内存大约为每个截止时间8个字节,等于64位系统上指针的大小(方法2所需)。

方法1的唯一风险是,如果您不经常使用它们,您可能会同时累积更多对象。您可以通过定期扫描和删除对象来缓解此问题。只要物体不会累积得太快,就可以相对不频繁地扫描。

答案 3 :(得分:0)

如果不断创建新对象并删除旧对象,请考虑使用在程序启动时创建一堆对象的对象池。如果用完,请动态增加对象数量。将对象数量增加一定百分比(10% - 25%),而不是一次增加一个。如果不再需要某个对象,则将其返回到对象池。如果考虑内存,请考虑使用算法删除对象池中的对象。例如,它可以删除75%的每5或10分钟未使用的对象。

要实现此目的,请考虑使用可用对象池列表以及正在使用的列表。您的对象应该具有可以调用以初始化现有对象的初始化方法。调用参数应该与构造函数非常相似。至于容器本身,您可能想要尝试使用向量和链接列表,看看哪个更快。如果您的应用需要搜索对象,那么std :: map或std :: unordered_map将是更好的选择。当计时器唤醒时,可以使用迭代器遍历整个使用中的列表。

至于定时器,你认为会更快 - 有500,000个定时器唤醒并每秒做一次,或者只有一个定时器每秒唤醒一次,通过一个500,000个对象的列表来查看是否一个对象应该返回到对象池?我认为很明显使用一个计时器更有效率。如果现在或将来有500,000个计时器在Windows上运行,我也会非常担心。我知道一些旧的Windows操作系统肯定会崩溃。计时器应该多久醒来一次?尝试尝试1到5秒之间的值。对于更长的唤醒时间,这将是内存消耗的折衷.vs。 CPU限制可缩短唤醒时间。

你的第二种方法听起来像一些垃圾收集者那样做。 Microsoft's .NET garbage collector被组织成代,其中短生命对象进入第0代,第一代使用寿命更长的对象,第二代使用寿命最长的对象。

如果进行多线程处理,则考虑每个线程使用一个对象池。每个对象池都有自己的计时器。

相关问题