我有一个Windows窗体应用程序。在主窗体内部有一个迭代大约3000次的循环,在新线程上创建一个类的新实例来执行一些计算。请记住,此设置使用线程池,当此循环只有大约100次迭代时,UI确实保持响应(100个要处理的资产)。但是一旦这个数字开始大量增加,UI就会锁定到eggtimer模式,因此写在表单上的列表框中的日志变得不可读。
我认为解决这个问题的最佳方法是使用背景工作者吗? 并且UI是锁定的,因为即使我使用了许多不同的线程(为了速度),UI本身也不在它自己的单独线程上?
建议的实施非常感谢。
因此,我们可以说,不是仅仅开火并排队处理3000个资产,我决定分批进行。我将如何高效地完成这项工作?我之前尝试添加“Thread.Sleep(5000);”在每批100个被解雇之后,整个事情似乎都被废弃了......
答案 0 :(得分:4)
更多线程不等于最高速度。事实上,太多线程等于速度较慢。如果您的任务只是CPU相关的,那么您应该只使用与核心一样多的线程,否则就会浪费资源。
经过3,000次迭代,你的表单线程试图创建一个线程,每次可能发生的事情是你正在最大化线程池并且表单挂起,因为它需要等待先前的线程完成才能完成分配一个新的。
显然ThreadPool
不起作用。我以前从未用线程检查过,所以我不确定。另一种可能性是,任务开始使用调用充满UI线程,此时它将放弃GUI。
答案 1 :(得分:4)
如果要创建3000个单独的线程,则需要推送ThreadPool类的documented limitation:
如果申请遭到破裂 大量的活动 线程池任务排队,使用 SetMinThreads方法增加了 最小空闲线程数。 否则,内置延迟 创建新的空闲线程可能会导致 瓶颈。
请参阅MSDN主题,了解为您的情况配置线程池的建议。
如果您的工作是CPU密集型的,那么拥有许多单独的线程将导致更多的开销而不是它的价值。但是,如果它非常密集,那么拥有大量线程可能会有所帮助。
.NET 4引入了对并行编程的出色支持。如果这是您的选择,我建议您have a look at that。
答案 2 :(得分:1)
在没有看到代码的情况下很难分辨 - 但是,根据您所描述的内容,有一个嫌疑人。
你提到你现在在ThreadPool上运行了这个。切换到BackgroundWorker不会显着改变任何东西,因为它也使用ThreadPool来执行。 (BackgroundWorker只是简化了调用调用......)
话虽如此,我怀疑问题是您的回复到ListBox的UI线程的通知。如果您过于频繁地调用,则在尝试“赶上”时,您的UI可能会变得无法响应。如果您通过Control.Invoke将过多的状态信息反馈给UI线程,则会发生这种情况。
否则,请确保您在ThreadPool上完成所有工作,并且您没有阻止UI线程,它应该可以工作。
答案 3 :(得分:1)
如果每个线程都记录了你的ui,那么每个写入的日志行都必须调用主线程。最好只缓存日志输出并且每100次迭代或类似的事情更新gui。
答案 4 :(得分:0)
由于我没有看到你的代码,所以这只是一些猜想非常有希望的猜测。
所有线程池都会对您的请求进行排队,然后在其他人完成工作时关闭新线程。现在3000线程听起来不是很多,但是如果有大量的处理正在进行,你可能会破坏你的CPU。
我不相信后台工作人员会帮忙,因为你最终会重新创建一个管理器来处理线程池给你的所有池。我认为你发现的问题是你有太多的数据分块正在进行中。我认为一个好的起点是限制你启动和维护的线程数量。线程池管理器可以轻松地执行此操作。找到一个平衡点,允许您在保持UI响应的同时处理数据。