【问题标题】:Multithreading a GUI using backgroundworkers使用后台工作程序对 GUI 进行多线程处理
【发布时间】: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 更新图表,所以我尝试从 BGW2DoWork 部分更新图表。

更新从 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


【解决方案1】:

好吧,不要那么频繁地更新。只需坚持固定的刷新率,并使用ConcurrentQueue 在读取数据的BackgroundWorker 和呈现数据的 GUI 之间传递数据点。一个简单的Timer 应该可以很好地工作 - 每五秒读取一次ConcurrentQueue 中的所有内容并更新图表。

不要从多个线程更新 UI。支票的存在是有原因的。

【讨论】:

  • @rwank 是的,同时 GUI 线程在做什么?还有任何其他你忘记你实际上在另一个线程上的线程?对 GUI 的访问仅限于 GUI 线程是有原因的,多线程是hard
【解决方案2】:

一个后台工作者就够了。

此操作的昂贵部分是;

  1. 同步回 UI 线程
  2. 在您执行此操作时阻止工作人员。

解决性能问题,最小化#1。不要发布每个项目,每隔x 毫秒发布很多项目。

事实上,我建议根本不要使用后台工作线程 - ReportProgress 事件会阻塞你的工作线程。

【讨论】:

  • 我上面提到的 10Fps 是我可以与ReportProgress 一起使用的最快更新速率,因此我为什么要寻找一种解决方法,让我可以直接更新图表而无需干扰主线程跨度>
【解决方案3】:

你试过enforce the events being handled吗?这将清空事件队列,以便表单对用户负责。不过,正如 Luaan 所指出的,您最好以固定速率更新 GUI。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-27
    • 1970-01-01
    • 1970-01-01
    • 2017-05-08
    • 1970-01-01
    • 2019-04-23
    相关资源
    最近更新 更多