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

本文关键字:方法 函数调用 错误 线程 运行 意想不到 如果 AsyncAwait | 更新日期: 2023-09-27 18:13:57

我试图在不冻结GUI线程的情况下执行一些耗时的操作。UpdateSomething方法在两个地方被调用,一次在我的ViewModel的构造函数中,一次在按钮单击(RelayCommand)。如果通过RelayCommand调用该方法,则该方法在WorkerThread中执行,但当方法调用来自构造函数时,则在主线程(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

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

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

Task.Factory.StartNew默认使用TaskScheduler.Current(您可以通过调用适当的覆盖来更改它的使用),而Task.Run使用TaskScheduler.Default

Task.Factory.StartNew不玩将与async/await的声明是不正确的,只是一些默认值可能不是你想要的常见情况(这是Task.Run引入的部分原因)。

:

  • http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx
  • 为什么是TaskScheduler。当前默认的TaskScheduler?

我之前也遇到过同样的问题。我在这里贴了一个小帖子:

今天我很紧张。我在一个新任务中包装的代码块上使用await/async。无论我做什么,它都会启动任务,但不会等待结果。

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

最后我把它改成了Task。

基本上你需要使用Task。运行,因为await不能很好地与Task.Factory.StartNew兼容

这个问题是由@Rene147回答的,但是他删除了他的回答。(不管出于什么原因)

我将简短地改写他所写的:

await/asyncn不能很好地与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也写了一篇关于它的短文。

我很乐意得到更多关于这个问题的信息,但我还是觉得很奇怪。