【发布时间】:2015-12-16 00:34:18
【问题描述】:
我通过Parallel.ForEach 编写了一个使用所有可用内核的程序。 ForEach 的列表包含约 1000 个对象,每个对象的计算需要一些时间(约 10 秒)。
在这种情况下,我设置了一个这样的计时器:
timer = new System.Timers.Timer();
timer.Elapsed += TimerHandler;
timer.Interval = 15000;
timer.Enabled = true;
private void TimerHandler(object source, ElapsedEventArgs e)
{
Console.WriteLine(DateTime.Now + ": Timer fired");
}
目前TimerHandler 方法是一个存根,以确保问题不是由该方法引起的。
我的期望是TimerHandler 方法将每 15 秒执行一次。但是,两次调用此方法之间的时间甚至达到了 40 秒,所以 25 秒太多了。
通过将new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount -1 } 用于Parallel.ForEach 方法,这不会发生,并且会看到预期的15 秒间隔。
我是否必须确保每个活动计时器始终有一个内核可用?似乎更奇怪了,因为“保留”可能是我计算的宝贵资源。
编辑:正如 Yuval 所指出的那样,ThreadPool.SetMinThreads 在池中设置了固定的最小线程数解决了这个问题。我还为Parallel.ForEach 方法尝试了new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }(所以在最初的问题中没有-1),这也解决了这个问题。但是,我没有很好的解释为什么这些修改解决了这个问题。也许创建了太多线程,以至于计时器线程“丢失”了“长时间”,直到再次执行。
【问题讨论】:
-
如果在执行并行循环之前明确设置线程池中的线程数,还会出现这种情况吗? (使用
ThreadPool.SetMinThreads) -
当您使用所有处理器时,您是否在跟踪处理器使用情况?如果是这样,由于 windows 处理消息泵的方式,所有事件的响应速度都会变慢。
-
我怀疑运行并行线程的线程(可能是运行计时器的同一线程)正在阻塞自己。如果您能找到一种在不同线程上运行计时器的方法,您的问题可能会消失。运行计时器的线程可能会有所不同,具体取决于您的应用的托管方式(例如 Windows 窗体与控制台应用)
-
@YuvalItzchakov 这似乎有效,谢谢。我已将其设置为固定值(即使我只有 4 个内核也尝试了 50)并且它可以工作。我也试过设置
new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }(所以没有-1),效果一样。 -
问题已解决 - 请解释一下?为什么设置这个可以解决问题,而不管值设置为什么?
标签: c# multithreading foreach timer parallel.foreach