3

我需要在预定义的时间以有效的方式运行数十万个函数,

我目前拥有的代码是这样的:

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”函数以使延迟时间尽可能低,(通过使用a来处理必要的线程同步Mutex

我想到的2个解决方案:

  1. 而不是有一个List<myclass>,我可以有一个像Dictionary<DateTime, List<myclass>>1 秒精度的字典,并且每秒运行适当的类对象,字典会将“nexttime”映射到“myclass”实例。
  2. 创建两个List<>s 或Queue<>s 而不是一个列表,它们将被命名为 'fastqueue' 和 'slowqueue' ,slowqueue 将拥有所有对象,fastqueue 将拥有所有即将需要工作的项目,然后有一个专用线程循环通过慢队列,并检查剩余时间并将其放入快速队列。

笔记:

  1. 真正的代码没有任何随机数据决定下一次运行时间,它实际上是基于一些计算,这只是一个示例。

  2. 每个项目运行时间不超过几分之一秒,每个项目在一小时内最多运行 4 次。ram 和 cpu 功率不是问题,我已经测试并在不同区域进行了优化以使其适合,尽管此处并未显示所有代码。

  3. 唯一浪费 cpu 时间的是返回 DateTime.Now > NextTime 的行
4

4 回答 4

3

我不能保证它可以解决您的问题,因为我不知道您有多少计算能力,但是您是否尝试过而不是从不同Parallel.ForEach的线程调用?Activator你可以这样做。

Parallel.ForEach(mylist, item =>
{
    item.DoStuff();
});

如果您想限制并发线程的数量,您可能还需要设置MaxDegreeOfParallelism调用时间。Parallel.ForEach如果我的回答不够清楚或不够详细,请发表评论。

编辑:正如评论正确指出的那样,DoStuff()在我的示例中将同步执行。使用Task.Factory.StartNew()或任何等效物来利用任务调度程序可能会有所帮助。然而,作者表示,大多数任务真的很小,并且在很短的时间内执行。出于这个原因,我认为实际的调度会导致不必要的开销,而不是在不同线程上串行执行。

于 2012-12-31T19:02:57.280 回答
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));
    }
}
于 2013-01-08T22:29:51.740 回答
1

增量队列 - 按超时时间排序的列表,是处理大量长时间超时的常用方法。我使用一个线程来管理列表。它等待输入 BlockingCollection 队列,超时设置为现在和列表头部项目的超时时间之间的间隔。如果等待超时,它会弹出并触发队列头部的项目,获取新的头部对象,重新计算其等待时间并再次等待输入队列(如果列表为空,超时设置为 INFINITE)。新的超时项目被推送到输入队列,线程在恢复其超时活动之前插入它们。

于 2013-01-09T09:14:00.730 回答
0

这取决于您尝试执行的任务的复杂性以及您拥有的硬件资源量,但我建议使用库来完成此类工作:Quartz.net可能很有用。

于 2012-12-31T19:03:39.683 回答