【问题标题】:Thread running a heavy method is slowing down the UI in C#运行繁重方法的线程正在减慢 C# 中的 UI
【发布时间】:2015-02-22 22:18:19
【问题描述】:

有谁知道为什么这段代码会拖慢 UI:

Thread trdGenerateTrajectory = new Thread(() => HeavyMethod());
trdGenerateTrajectory.Start();
trdGenerateTrajectory.Join();

这应该在与主线程不同的线程中,对吗?如果是这样,为什么运行它会减慢/冻结 UL?

编辑:感谢您的 cmets。我删除了 Join(),但它仍然冻结了 UI。有什么想法吗?

更新:HeavyMethod() 方法正在调用我创建的 Matlab dll 中的方法。 dll中的方法为机器人生成操纵轨迹。我的项目是一个重型机器人项目,它与许多硬件/设备进行通信。该项目有 12 个后台工作人员和一个计时器。计时器负责更新 UI 及其上的所有文本/颜色/图像/...。到目前为止,我对后台工作程序和计时器没有任何问题,无论他们运行的任务有多么繁重,我从未看到计时器和 UI 更新有任何延迟或停止。但是,当我在 Matlab dll 中调用此特定方法时,我看到 UI 完全停止更新,直到该方法完成。这是我的经历:

  1. 我使用线程(上面的代码)没有运气。
  2. 然后我将方法和运行方法后的进程移到另一个后台工作程序中,但还是没有运气。

然后我意识到我的表单上只有一些文本框遇到了这个问题。它们是从同一个 Matlab dll 的另一种方法中获取值的那些。那个时候我才意识到这个问题与线程/后台工作者无关,与 Matlab 运行方法的方式有关。也许它是单线程的!?无论如何,如果我为这个生成轨迹的特定方法制作单独的 dll 可能会有所帮助,所以我创建了另一个 dll,但我遇到了完全相同的问题。似乎 Matlab dll 一次只能运行一种方法,无论您是从不同的线程还是从单独的 dll 调用它们。我相信我应该在单独的 SO 问题中提出这个问题,我会的,但是与此同时,您对此有何评论? (更新:我没有收到任何回复,所以我发布了一个新问题:Calling two functions from a single Matlab dll at the same time

【问题讨论】:

  • 你在使用 cpusets - 并且代码是在多核系统上吗?
  • 异步与同步、调度程序线程等可以帮助您。您创建了一个线程,如何以及何时运行它。 UI 线程在运行时会发生什么?有进度条在运行吗?
  • 这是什么程序? Windows 窗体?
  • 是的,它在 8 核系统上。我有一个更新texboxes的计时器。当我运行上面的代码时,文本框中的文本会停止更新,直到这个线程完成。我的程序是 Winform。
  • 如果您的 UI 在移除 Join() 后仍处于阻塞状态,则 HeavyMethod() 中的代码未正确使用主 UI 线程。也许你在那里有一个 Invoke() 调用?...

标签: c# multithreading user-interface freeze


【解决方案1】:

尽管您在后台线程上运行计算,但您的 Join 调用会导致您的 UI 线程在您的计算完成之前一直阻塞。

今天执行此操作的正确方法是使用 asyncawait 关键字。如果您真的想将自己限制在线程中,您可以在计算完成后使用线程内的Invoke 调用将控制分派回 UI 线程:

Thread trdGenerateTrajectory = new Thread(() => 
{
    HeavyMethod();

    this.Invoke(new Action(() =>
    {
         // Update UI here.
    }));
});

trdGenerateTrajectory.Start();
// trdGenerateTrajectory.Join(); <- do not block

编辑:假设您想要运行计算以响应某些按钮单击(或任何其他事件),您可以在事件处理程序中使用异步模式,如下所示:

private async void myButton_Click()
{
    await Task.Run(HeavyMethod);

    // Update UI here.
}

【讨论】:

  • 谢谢,你能告诉我如何使用 async 和 await 来解决这个问题吗?
  • @NESHOM:更新答案。
  • 谢谢。我尝试了没有 Join() 的简单代码。它仍然冻结用户界面。你知道是什么原因吗?
  • “冻结” UI 是指您没有获得任何进度更新,还是您的 UI 完全停止响应用户输入?如果是后者,那么就像 Idle_Mind 所说的那样,您的 HeavyMethod 可能会在内部调度一些对 UI 线程的调用。这甚至可能发生在您调用的库中;例如,Office 对象模型透明地运行 UI 线程上的所有调用。您能否就HeavyMethod 的作用向我们提供更多背景信息?
  • 另一种可能性:您的HeavyMethod 可能会产生更多并行处理(通过子线程或任务),从而将您的 CPU 使用率提高到 100%。因此,尽管 UI 线程是空闲的,但操作系统很难为其分配一个核心来运行。同样,这些只是猜测;如果您能向我们展示一个简单的例子来说明HeavyMethod 中发生的事情,那将是最好的。
【解决方案2】:

您正在启动线程并立即加入它。加入线程意味着您正在等待它结束。

通常,用户界面是单线程的。这意味着您的方法需要返回才能处理另一个事件。

【讨论】:

  • HeavyMethod() 正在生成一些数据。这意味着我需要在线程完成后立即处理数据。我正在尝试使用类似于后台工作人员的 DoWork() 方法,但仅使用线程。可能吗?我相信如果我将 HeavyMethod() 方法移到后台工作程序,它不会减慢 UI,对吗?
  • 您始终可以在 HeavyMethod() 调用之后在 lambda 中进行处理,并删除对 Join() 的调用。
猜你喜欢
  • 2015-10-21
  • 1970-01-01
  • 1970-01-01
  • 2021-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-21
  • 1970-01-01
相关资源
最近更新 更多