我需要在预定义的时间以有效的方式运行数十万个函数,
我目前的代码是这样的:
class myclass
{
public DateTime NextTime = DateTime.Now;
Random rand = new Random();
public void DoStuff()
{
if (NeedToWork())
{
// do some complex stuff on a 2nd thread.
NextTime = DateTime.Now.AddSeconds(rand.Next(60, 3600));
}
}
public bool NeedToWork()
{
return DateTime.Now > NextTime;
}
}
从计时器运行的调用函数:
static List<myclass> mylist = new List<myclass>();
static void Activator()
{
foreach (var item in mylist)
{
item.DoStuff();
}
}
我的问题是当集合中有大量项目时,所有这些项目需要花费很长时间,导致一些DoStuff()函数在某些情况下运行时间超过一分钟。
目前,同时从不同的线程调用“Activator”函数以使延迟时间尽可能低(使用Mutex
来处理必要的线程同步)
我想到的两个解决方案:
List<myclass>
,我可以有一个像Dictionary<DateTime, List<myclass>>
这样的字典,精度为1秒,每秒运行相应的类对象,dictionay将映射'nexttime'到'myclass'实例。List<>
s或Queue<>
s而不是一个列表,它们将被命名为'fastqueue','slowqueue',slowqueue将拥有所有对象,fastqueue将拥有所有项目很快就需要工作,然后有一个专用线程循环通过慢队列,并检查剩余时间并将其放入快速队列。注意:
实际代码没有任何随机数据确定下一个运行时间,它实际上是基于某些计算,这只是一个样本。
每个项目运行所需的时间不会超过一分之一秒,并且每个项目在一小时内最多只运行4次。 ram和cpu power不是问题,我已经测试并在不同的区域进行了大量的优化以使其适合,尽管这里没有显示所有代码。
答案 0 :(得分:3)
我无法保证它能解决您的问题,因为我不知道您有多少计算能力,但您是否尝试过Parallel.ForEach
而不是从不同的线程调用Activator
?你可以这样做。
Parallel.ForEach(mylist, item =>
{
item.DoStuff();
});
如果要限制运行的并发线程数,可能还需要在调用MaxDegreeOfParallelism
时设置Parallel.ForEach
。如果我的答案不清楚或不够详细,请发表评论。
编辑:正如评论所述,我的示例中的DoStuff()
将同步执行。使用Task.Factory.StartNew()
或任何等价物来利用任务调度程序可能会有所帮助。然而,作者指出,大多数任务都很小,并且在很短的时间内执行。出于这个原因,我认为实际的调度会导致不必要的开销,而不是在不同的线程上执行串行执行。
答案 1 :(得分:3)
您可能希望维护已排序的队列或工作树,并按运行时间排序。
然后你的常规间隔定时器循环运行队列中的前N个项目,当项目超出当前间隔时间时停止,因为不需要进一步查看。
在生成要添加到队列的新工作时,使用已排序的数据结构,插入时应正确放置以保持排序。
(在添加和删除队列时,您还需要担心线程安全。)
(仅供参考,调度算法有很多变化。)
另外请注意,虽然不确定它是否对您有用,但是在使用这些基于时间的公式时,您可能会考虑使用DateTime.Now快照多次使用,否则您可以“松散的“如果此线程在调用DateTime.Now
之间中断的时间public void DoStuff(DateTime now)
{
if (NeedToWork(now))
{
// do some complex stuff on a 2nd thread.
NextTime = now.AddSeconds(rand.Next(60, 3600));
}
}
答案 2 :(得分:1)
增量队列 - 按超时时间排序的列表,是处理大量长超时的常用方法。我使用一个线程来管理列表。它等待输入的BlockingCollection队列,其超时设置为now和介于列表头部的项目的超时时间之间的时间间隔。如果等待超时,它会弹出并触发队列头部的项目,获取新的头部对象,重新计算其等待时间并再次等待输入队列(如果列表为空,则超时设置为INFINITE)。新的超时项被推送到输入队列,并且线程在恢复其超时活动之前插入它们。
答案 3 :(得分:0)
这取决于您尝试执行的任务的复杂程度以及您拥有的硬件资源量,但我建议使用库来完成此类工作:Quartz.net可能很有用。