【发布时间】:2015-06-10 11:44:47
【问题描述】:
我的项目中有 2 个后台工作人员:
BGW1:第一个worker用于从控制器读取数据并将数据转换为正确的格式
BGW2:第二个worker用于使用ReportProgress功能将转换后的数据和对象传递给GUI
整个过程需要尽可能实时,并且消息大约每 0.5 毫秒发送一次。当 MainThread 必须每 5-10 毫秒更新 800 个点时,它会很快变得慌乱。
如果我以超过 10fps 的速度更新,这会导致 GUI 无响应。
我在网上找到了一个解决方案,是这样的: Alternate Way of Multithreaded GUI
我尝试通过设置将这种方法应用于我的后台工作人员
// Prevent the framework from checking what thread the GUI is updated from.
theMainForm.CheckForIllegalCrossThreadCalls = false;
在主窗体中。据我了解,这允许我从单独的线程而不是主线程更新 gui。
在主线程中使用这一行应该意味着我可以从非主线程的其他线程访问 GUI 元素,并且我不需要使用 ReportProgress
更新图表,所以我尝试从 BGW2 的 DoWork 部分更新图表。
更新从 DoWork 开始,但它似乎仍然只是将数据引用到 MainThread,然后该线程更新图表,这再次导致 GUI 无法使用。
我是否必须完全摆脱后台工作人员并且只使用线程来解决链接中的问题?或者有什么技巧可以让这个方法与后台工作人员一起工作。
【问题讨论】:
-
您将通过在不是 UI 线程的线程上简单地执行长时间运行的操作来获得大部分收益。仅当您有可以并行完成的不同任务而无需相互依赖或共享资源时,添加额外的后台线程才会有帮助。
-
您应该使用任务而不是后台工作人员,但这只会负责异步处理传入事件,例如使用异步事件处理程序。为了减少 UI 的更新频率,您需要限制传入的事件,例如使用 Reactive Extensions 中的 Throttle 作为 shown here 来捆绑和处理事件,仅每 X 毫秒或 Y 事件
-
这是第三个最常见的线程错误,一个 fire-hose 问题。与前 2 个很容易诊断不同,任务管理器可以显示您的 UI 线程正在燃烧 100% 核心。通过将 CheckForIllegalCrossThreadCalls 设置为 false,您现在还可以启用其他错误、线程竞争和死锁。完全无法调试的那种。非常糟糕的主意。如果你不能让人眼专注于 UI 线程,它只需要 20 次更新/秒就开始变得模糊,那么你做错了。经常这样做是没有任何意义的。
-
@Hans Passant UI 线程不会以 100% 的速度燃烧,它只是足够高以至于用户输入会延迟,因为传递给主线程的数据量很大。这就是我目前将应用程序限制为 10fps 的原因。这似乎是 GUI 保持 100% 交互并且图表仍然足够流畅的最佳点。
标签: c# multithreading winforms user-interface