1

我正在使用 async / await 模式对对象执行一些 CPU 繁重的操作(我的方法是可等待的),它按预期工作而不会阻塞 UI 线程。

但是,当我将对象作为参数传递给新窗口的 ctor 时(新窗口是需要访问已处理对象的日志记录窗口),我的 UI 线程阻塞(我有点理解为什么)。

为了解决这个问题,我可以将计算的执行包装在

Task.Run(async () => { await _myObject.PerformCalculations(); });

然后只需调用

var logWindow = new LogWindow(_myObject);
logWindow.Show();

这可行(当然),但是当对象引发事件时,我有很多调度程序调用,如果没有 Task.Run 调用,我就不必处理这些调用。

所以,我的问题是,我可以在没有 Task.Run 调用的情况下以某种方式将对象传递到日志记录窗口而不阻塞我的 UI 线程吗?

编辑

我很抱歉这个精简的例子,我实际上是想让这个问题尽可能简单易懂并且惨遭失败。

以更一般的方式:我有一个在某些条件下引发事件的对象。引发事件时,我想在 UI 上执行更新。事件总是从使用 Task.Run(...) 创建的线程触发。因此,调度程序调用 UI 线程。所以,我想使用 async / await 执行计算(已经工作)并将对象传递到我的日志窗口(块)。

当我使用 Task.Run 时,当然一切正常,但无论我从 UI 线程订阅对象的事件,我都必须使用调度程序调用 UI 线程,因为该事件是从 Task.Run 创建的线程触发的。我想避免这些调度程序调用。事实上,如果我不将对象传递到日志记录窗口并调用 Show() 方法,UI 线程就不会阻塞,一切都会按预期工作。事件处理程序中不需要调度程序调用。

4

2 回答 2

1

很难清楚地了解您的情况。但在我看来,你可以做一些重构。

考虑一下PerformCalculations:这是一个返回的方法Task(因此将自己宣传为async- 友好的),它会占用大量 CPU (因此实际上不是 async- 友好的)。我首先要看的是划分逻辑,PerformCalculations以便受 CPU 限制的部分使用它们自己的Task.RunPerformCalcuations作为一种async不会(直接)影响 CPU 的方法:

public async Task PerformCalculationsAsync()
{
  while (...)
  {
    await Task.Run(<next calculations>);
    RaiseEvent();
  }
}

这种重构的重点是将 CPU 代码Task.Run与 UI-ish 代码引发事件分开。IProgress<T>如果您的事件在逻辑上是进度更新,或者这种重构对您的代码来说太难了,也可以考虑使用标准方法;IProgress<T>.Report可以从任何线程调用。

async您可能还会发现我关于构造函数async属性(尤其是数据绑定部分)的帖子很有帮助。

于 2013-03-15T12:22:21.703 回答
0
// awaitable as well - await this in another async void/Task method (e.g. commanding)
public async Task MyAsyncProcess()
{
    await _myObject.PerformCalculations();
    var logWindow = new LogWindow(_myObject);
}

Task.Run()同步执行异步方法,因此在这种情况下,您几乎不需要使用 async/await 模式。在执行代码的地方创建方法async并在其他地方等待它。或者使用一些FireAndForget逻辑。

于 2013-03-15T08:11:33.660 回答