异步等待和共享对象

时间:2013-03-15 08:08:12

标签: c# wpf multithreading asynchronous async-await

我正在使用async / await模式对一个对象执行一些CPU繁重的操作(我的方法是可以的),它可以在不阻塞UI线程的情况下运行。

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

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

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线程,因为事件从任务的线程触发。运行已创建。我想避免这些调度员电话。 实际上,如果我不将对象传递给日志记录窗口,并调用Show()方法,则UI线程不会阻塞,一切都会按预期工作。事件处理程序中不需要调度程序调用。

2 个答案:

答案 0 :(得分:1)

很难清楚地了解你的情况。但它看起来像你可以做一些重构。

考虑PerformCalculations:这是一个返回Task的方法(因此将自己宣传为async - 友好),这会占用大量CPU(因此实际上并不是 async - 友好)。我要看的第一件事就是将PerformCalculations中的逻辑分开,以便CPU绑定部分使用自己的Task.Run,将PerformCalcuations保留为async方法。 '(直接)击中CPU:

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

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

您也可以在async constructorsasync properties(特别是数据绑定部分)上找到我的帖子。

答案 1 :(得分: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逻辑。