.NET 线程池 - WinForms UI 无响应
场景
我有一个 Windows 窗体应用程序。主窗体内部有一个循环,迭代大约 3000 次,在新线程上创建类的新实例来执行一些计算。请记住,此设置使用线程池,当此循环只有大约 100 次迭代(要处理 100 个资产)时,UI 确实保持响应。但一旦这个数字开始大幅增加,UI 就会锁定到 Eggtimer 模式,因此写入表单列表框的日志将变得不可读。
问题
我认为解决这个问题的最佳方法是使用后台工作人员是否正确? UI 是否会锁定,因为即使我使用许多不同的线程(为了速度),UI 本身并不位于其自己的单独线程上?
非常感谢建议的实施。
编辑!!
因此,我们可以说,我决定以 100 个为一组进行批量处理,而不是仅仅发送并排队 3000 个资产进行处理。我将如何有效地做到这一点?我早些时候尝试添加“Thread.Sleep(5000);”每一批 100 个都被发射之后,但整个事情似乎一团糟......
Scenario
I have a Windows Forms Application. Inside the main form there is a loop that iterates around 3000 times, Creating a new instance of a class on a new thread to perform some calculations. Bearing in mind that this setup uses a Thread Pool, the UI does stay responsive when there are only around 100 iterations of this loop (100 Assets to process). But as soon as this number begins to increase heavily, the UI locks up into eggtimer mode and the thus the log that is writing out to the listbox on the form becomes unreadable.
Question
Am I right in thinking that the best way around this is to use a Background Worker?
And is the UI locking up because even though I'm using lots of different threads (for speed), the UI itself is not on its own separate thread?
Suggested Implementations greatly appreciated.
EDIT!!
So lets say that instead of just firing off and queuing up 3000 assets to process, I decide to do them in batches of 100. How would I go about doing this efficiently? I made an attempt earlier at adding "Thread.Sleep(5000);" after every batch of 100 were fired off, but the whole thing seemed to crap out....
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
如果您要创建 3000 个单独的线程,则将面临记录在案的限制< ThreadPool类的/a>:
请参阅该 MSDN 主题,获取针对您的情况配置线程池的建议。
如果您的工作是 CPU 密集型的,那么拥有那么多单独的线程将导致超出其价值的开销。但是,如果 IO 非常密集,那么拥有大量线程可能会有所帮助。
.NET 4 引入了对并行编程的出色支持。如果这是您的选择,我建议您看看。
If you are creating 3000 separate threads, you are pushing a documented limitation of the ThreadPool class:
See that MSDN topic for suggestions to configure the thread pool for your situation.
If your work is CPU intensive, having that many separate threads will cause more overhead than it's worth. However, if it's very IO intensive, having a large number of threads may help things somewhat.
.NET 4 introduces outstanding support for parallel programming. If that is an option for you, I suggest you have a look at that.
更多线程并不等于最高速度。事实上,太多的线程等于更低的速度。如果您的任务只是与 CPU 相关,那么您应该只使用与核心数量一样多的线程,否则就会浪费资源。
经过 3,000 次迭代,并且您的表单线程每次都尝试创建一个线程,可能发生的情况是您已最大化线程池,并且表单挂起,因为它需要等待先前的线程完成才能分配新的线程one.显然
ThreadPool
不能以这种方式工作。我以前从未用线程检查过它,所以我不确定。另一种可能性是任务开始用调用淹没 UI 线程,此时它将放弃 GUI。More threads does not equal top speed. In fact too many threads equals less speed. If your task is simply CPU related you should only be using as many threads as you have cores otherwise you're wasting resources.
With 3,000 iterations and your form thread attempting to create a thread each time what's probably happening is you are maxing out the thread pool and the form is hanging because it needs to wait for a prior thread to complete before it can allocate a new one.Apparently
ThreadPool
doesn't work this way. I have never checked it with threads before so I am not sure. Another possibility is that the tasks begin flooding the UI thread with invocations at which point it will give up on the GUI.如果不看代码,很难判断 - 但是,根据您所描述的内容,有一个嫌疑人。
您提到您现在已在线程池上运行它。切换到BackgroundWorker不会显着改变任何东西,因为它也使用ThreadPool来执行。 (BackgroundWorker 只是简化了调用...)
话虽如此,我怀疑问题是您将通知返回到 ListBox 的 UI 线程。如果您调用得太频繁,您的 UI 在尝试“赶上”时可能会变得无响应。如果您通过 Control.Invoke 将太多状态信息反馈回 UI 线程,则可能会发生这种情况。
否则,请确保所有工作都在 ThreadPool 上完成,并且不会阻塞 UI 线程,并且它应该可以工作。
It's difficult to tell without seeing code - but, based on what you're describing, there is one suspect.
You mentioned that you have this running on the ThreadPool now. Switching to a BackgroundWorker won't change anything, dramatically, since it also uses the ThreadPool to execute. (BackgroundWorker just simplifies the invoke calls...)
That being said, I suspect the problem is your notifications back to the UI thread for your ListBox. If you're invoking too frequently, your UI may become unresponsive while it tries to "catch up". This can happen if you're feeding too much status info back to the UI thread via Control.Invoke.
Otherwise, make sure that ALL of your work is being done on the ThreadPool, and you're not blocking on the UI thread, and it should work.
如果每个线程都将某些内容记录到您的用户界面,则每个写入的日志行都必须调用主线程。最好缓存日志输出并仅每 100 次迭代或类似的事情更新 gui。
If every thread logs something to your ui, every written log line must invoke the main thread. Better to cache the log-output and update the gui only every 100 iterations or something like that.
因为我还没有看到你的代码,所以这只是很多猜测和一些高度希望受过教育的猜测。
线程池所做的就是将您的请求排队,然后在其他线程完成其工作时触发新线程。现在 3000 个线程听起来并不是很多,但如果正在进行大量处理,您可能会损坏您的 CPU。
我不相信后台工作人员会提供帮助,因为您最终将重新创建一个管理器来处理线程池为您提供的所有池化。我认为你更多的问题是你正在进行太多的数据分块。我认为一个好的起点是限制启动和维护的线程数量。线程池管理器可以轻松地让您做到这一点。找到一个平衡点,让您可以在处理数据的同时保持 UI 的响应能力。
Since I haven't seen your code so this is just a lot of conjecture with some highly hopefully educated guessing.
All a threadpool does is queue up your requests and then fire new threads off as others complete their work. Now 3000 threads doesn't sounds like a lot but if there's a ton of processing going on you could be destroying your CPU.
I'm not convinced a background worker would help out since you will end up re-creating a manager to handle all the pooling the threadpool gives you. I think more you issue is you've got too much data chunking going on. I think a good place to start would be to throttle the amount of threads you start and maintain. The threadpool manager easily allows you to do this. Find a balance that allows you to process data while still keeping the UI responsive.