如何在给定时间处理(动态添加)项目?

时间:2014-01-04 15:07:30

标签: c# timer task scheduler priority-queue

我有一个带有时间戳(将来)的(concurrent) priority queue 作为键和一个应该被调用的函数(/应该处理的项)作为值。我不想为每个项目附加一个计时器,因为它有很多。我宁愿选择调度程序线程/任务。

这样做的好策略是什么?


运行调度程序的线程...(后跟伪代码)

// scheduler
readonly object _threadLock = new object();
while (true)
{
    if(queue.Empty) 
    {
        Monitor.Wait(_threadLock);
    } 
    else 
    {
        var time = GetWaitingTimeForNextElement();

        if(time > 0)
          Monitor.Wait(_threadLock, time);
        else
          // dequeue and process element
    }  
}

...在添加元素时(以空队列或添加新的第一个元素)发出脉冲?

// element enqueued 
Monitor.Pulse(_threadLock);

或者使用Task.ContinueWith(...)以某种方式链接(Task.Delay(int, CancellationToken ))任务?如果新的第一个元素入队,则需要一些逻辑来中止等待,或者如果没有人正在运行则需要创建新任务。感觉就像有一个更简单的解决方案我现在没有得到。 :)


或使用计时器(非常伪代码,只是为了得到这个想法)......

System.Timers.Timer x = new System.Timers.Timer().Start();

x.Elapsed += (sender, args) =>
{
    // dequeue and process item(s)

    x.Interval = GetWaitingTimeForNextElement(); // does this reset the timer anyway?
}

...并在添加元素时更新间隔(如上所述)。

// element enqueued 
x.Interval = updatedTime;

我也关注等待方法/定时器的精确度:毫秒是非常粗糙的(虽然它可能有效)是否有更好的选择?

人体工程学...

这又是一堆问题/想法 - 对不起 - 但是有很多选择和担忧很难得到概述。总结一下:为动态传入的项目实施(精确)时间安排系统的最佳方法是什么?

我感谢所有的提示和答案!非常感谢。

1 个答案:

答案 0 :(得分:1)

我建议这样做:

  1. 创建一个名为TimedItemsConcurrentPriorityQueue<TKey, TValue>的类,该类继承自ConcurrentPriorityQueue<TKey, TValue>

  2. TimedItemsConcurrentPriorityQueue<TKey, TValue>类中实现一个名为ItemReady的事件,根据时间戳,当项目准备好(进行处理)时会触发该事件。您可以根据需要使用单个计时器并根据需要更新计时器,方法是根据需要隐藏EnqueueInsertRemove和其他方法(或者通过修改ConcurrentPriorityQueue<TKey, TValue>的来源和将这些方法设为虚拟,以便覆盖它们。)

  3. 实例化TimedItemsConcurrentPriorityQueue<TKey, TValue>的单个实例,让我们调用该变量itemsWaitingToBecomeReady。

  4. 实例化BlockingCollection<T>的单个对象,让我们称之为变量itemsReady。使用constructor that takes an IProducerConsumerCollection<T>并向其传递ConcurrentPriorityQueue<TKey, TValue>的新实例(它继承IProducerConsumerCollection<KeyValuePair<TKey,TValue>>

  5. 每当在itemsWaitingToBecomeReady中触发事件ItemReady时,您将该项目解除并将其排入itemsReady。

  6. 使用BlockingCollection<T>.GetConsumingEnumerable方法处理itemsReady中的项目,使用如下新任务:

  7. Task.Factory.StartNew(() =>
    {
      foreach (var item in itemsReady.GetConsumingEnumerable())
      {
        ...
      }
    }