use*_*422 11 c# foreach multithreading timer parallel.foreach
我编写了一个使用所有可用内核的程序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");
}
Run Code Online (Sandbox Code Playgroud)
目前,该TimerHandler方法是一个存根,以确保问题不是由此方法引起的.
我的期望是该TimerHandler方法将每隔约15秒执行一次.但是,两次调用此方法之间的时间甚至达到40秒,因此25秒太多.通过使用new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount -1 }该Parallel.ForEach方法,这不会发生,并且可以看到预期的15秒间隔.
我是否打算确保每个活动计时器始终有一个核心可用?似乎有点奇怪,因为"保留"可能是我计算的宝贵资源.
编辑:如Yuval所示,通过ThreadPool.SetMinThreads解决问题设置池中固定的最小线程数.我也试过new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }(所以没有-1初始问题)这个Parallel.ForEach方法,这也解决了问题.但是,我没有很好的解释为什么这些修改解决了这个问题.也许有很多线程被创建,计时器线程在"很长"的时间内"丢失",直到再次执行.
该类Parallel使用称为自复制任务的内部 TPL 设施。它们旨在消耗所有可用的线程资源。我不知道有什么样的限制,但似乎它是消耗一切的。几天前我已经回答过基本相同的问题。
这个Parallel班级很容易产生大量的任务,没有任何限制。很容易激发它产生无限的线程(每秒 2 个)。我认为Parallel如果没有手动指定 max-DOP,该类将无法使用。它是一颗定时炸弹,在生产过程中在负载下随机爆炸。
Parallel在许多请求共享一个线程池的 ASP.NET 场景中尤其有害。
更新:我忘了说重点了。计时器滴答声将排队到线程池中。如果池已饱和,它们就会排队并稍后执行。(这就是为什么计时器滴答可以同时发生或在计时器停止后发生的原因。)这解释了您所看到的内容。解决这个问题的方法是解决池过载问题。
针对这种特定情况的最佳解决方案是使用具有固定线程数量的自定义任务调度程序。Parallel可以使用该任务调度程序。Parallel Extension Extras 有这样一个调度程序。从全局共享线程池中获取该工作。通常,我会推荐 PLINQ,但它无法使用调度程序。从某种意义上说,Parallel 和 PLINQ 都是不必要的受损 API。
不要使用ThreadPool.SetMinThreads. 不要搞乱全局进程范围的设置。就不要管可怜的线程池了。
另外,不要使用,Environment.ProcessorCount -1因为这会浪费一个核心。
计时器已经在它自己的线程中执行
定时器是操作系统内核中的一个数据结构。在必须排队之前没有线程。不确定它到底是如何工作的,但滴答最终会排队到 .NET 中的线程池中。那就是问题开始的时候。
作为解决方案,您可以启动一个在循环中休眠的线程以模拟计时器。但这是一个黑客行为,因为它没有解决根本原因:超载的线程池。
| 归档时间: |
|
| 查看次数: |
931 次 |
| 最近记录: |