C# 如何在给定时间处理(动态添加)项?
我有一个以时间戳(将来)为键的函数,当到达时间作为值时,应该调用该函数(/应该处理的项)。我不想在每个项目上都附加一个计时器,因为有很多。我宁愿使用调度程序线程/任务 这样做的好策略是什么?C# 如何在给定时间处理(动态添加)项?,c#,timer,task,scheduler,priority-queue,C#,Timer,Task,Scheduler,Priority Queue,我有一个以时间戳(将来)为键的函数,当到达时间作为值时,应该调用该函数(/应该处理的项)。我不想在每个项目上都附加一个计时器,因为有很多。我宁愿使用调度程序线程/任务 这样做的好策略是什么? 使用运行调度程序的线程。。。(下面是伪代码) …并在添加元素(到空队列或添加新的第一个元素)时脉冲 或者使用Task.Delay(int,CancellationToken)以某种方式链接(Task.ContinueWith(…))任务?如果新的第一个元素排队,则需要一些逻辑来中止等待;如果没有人在运行
使用运行调度程序的线程。。。(下面是伪代码) …并在添加元素(到空队列或添加新的第一个元素)时脉冲
或者使用
Task.Delay(int,CancellationToken)
以某种方式链接(Task.ContinueWith(…)
)任务?如果新的第一个元素排队,则需要一些逻辑来中止等待;如果没有人在运行,则需要一些逻辑来创建新任务。感觉有一个更简单的解决方案我现在还没有
或者使用计时器(非常伪代码,只是为了得到这个想法) …并在添加元素时更新间隔(如上所述)
我还关心等待方法/计时器的精度:毫秒是相当粗糙的(尽管它可能会工作),有更好的选择吗 因此。。。 这又是一堆问题/想法-抱歉-但是有太多的选择和顾虑,很难得到一个概述。因此,总结一下:为动态进货项目实施(精确)时间安排系统的最佳方法是什么?
我感谢所有的提示和答案!非常感谢。我建议这样做:
TimedItemsConcurrentPriorityQueue的类,该类继承自
TimedItemsConcurrentPriorityQueue
类中实现一个名为ItemReady的事件,该事件根据时间戳在项目准备就绪(待处理)时触发。您可以使用单个计时器,并根据需要通过隐藏排队
、插入
、删除
和其他方法(或者通过修改ConcurrentPriorityQueue
的源并使这些方法虚拟化,以便可以覆盖它们)来更新计时器TimedItemsConcurrentPriorityQueue
的单个实例,让我们调用变量itemsWaitingToBecomeReadyBlockingCollection
的单个对象,让我们调用变量itemsrady。使用并向其传递一个新的ConcurrentPriorityQueue
(它继承了IProducerConsumerCollection
)你看了吗?@DanAbramov我觉得我应该看一下,但进入Rx似乎是另一件“大事”(?),所以目前我宁愿找一个没有它的解决方案。或者,您认为这是首选的解决方案吗?(好的,我一定会把它放在我的名单上。)谢谢你的回复。这绝对是件大事。但是,如果异步序列处理多于一个地方,就应该认真考虑它。我喜欢阻塞集合的“无休止的迭代”特性。使用ConcurrentPriorityQueue作为数据源(而不是空构造函数)的想法是什么?这样做
T
实际上就是KeyValuePair
,所有键都不包含任何信息(0或当前时间,具体取决于实现)。(但是,我同意在实现更通用版本的itemsrady
时使用它,它不依赖于键。)@mvondano:在以下场景中,在BlockingCollection中使用ConcurrentPriorityQueue非常有用:假设您正在处理一个需要很长时间才能处理的项目。在处理过程中,您将一个项目添加到itemsWaitingToBecomeReady,该项目也将准备就绪,然后移动到ItemsReady。之后,将另一项添加到itemsWaitingToBecomeReady,但其时间戳早于上一项。此项目也将移动到ItemsReady。在BlockingCollection中使用ConcurrentPriorityQueue时,即使在这种情况下,下一项也是正确的项。我明白了!谢谢你的解释!
// 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);
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;
Task.Factory.StartNew(() =>
{
foreach (var item in itemsReady.GetConsumingEnumerable())
{
...
}
}