AsyncAwait导致意外的方法行为,如果从构造函数调用,则方法在错误的线程中运行

时间:2013-05-16 11:06:32

标签: c# wpf task async-await

我试图在不冻结GUI线程的情况下做一些耗时的操作。 UpdateSomething方法在我的ViewModel的构造函数中在两个位置调用一次,在按钮单击(RelayCommand)上调用一次。如果方法是通过RelayCommand调用的,则在WorkerThread中执行,但是当方法调用来自构造函数时,在MainThread(GUI)中运行。

导致此奇怪行为的原因是什么?我通过IntelliTrace仔细检查了几次。

这是有问题的方法:

private async void UpdateSomething()
{
    var item = await Task.Factory.StartNew(() =>this.DoSomething("I should run async"));
    this.TestItem = item;
}

我正在使用WPF和.Net 4.5

3 个答案:

答案 0 :(得分:4)

我刚才遇到了同样的问题。我发了一篇关于它的帖子here

  

今天我有一个重要的头发拉动时刻。我在包含在新任务中的代码块上使用了await / async。无论我做了什么,它都会启动任务但不等待结果。

     

经过多次挫折之后,我发现使用await Task.Factory.StartNew并不能很好地等待。

     

最后,我只是将其更改为Task.Run然后工作正常。

基本上您需要使用Task.Run,因为awaitTask.Factory.StartNew不能很好地匹配

答案 1 :(得分:4)

对于Task s操作在主线程上运行的情况,最可能的原因是方法UpdateSomething是从另一个Task内调用的({{1}计划在主线程上运行的)。在这种情况下,Task是主线​​程TaskScheduler.Current而不是TaskScheduler哪个队列工作到线程池。

TaskScheduler.Default默认使用Task.Factory.StartNew(您可以通过调用相应的覆盖来更改其使用的内容),而TaskScheduler.Current使用Task.Run

TaskScheduler.Default没有播放的声明将使用async / await是不正确的,只是某些默认值可能不是您想要的常见情况(这是引入Task.Factory.StartNew的部分原因。)

请参阅:

答案 2 :(得分:0)

@ Rene147回答了这个问题,但他删除了答案。 (无论出于何种原因)

我将简要地重述他所写的内容:

await / asycn与Task.Factory.StartNew()的效果不佳。

只需将Task.Factory.StartNew替换为Task.Run,一切都应该有效:

private async void UpdateSomething()
{
    //not working when call comes from constructor
    //var item = await Task.Factory.StartNew(() =>this.DoSomething("I should run async"));
    //working
    var item = await Task.Run(() =>this.DoSomething("I run async!"));
    this.TestItem = item;
}

Rene147也写了一篇关于它的简短blogpost

很高兴获得有关此问题的更多信息,对我来说仍然很奇怪。