3

我正在尝试在不冻结 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

4

3 回答 3

4

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

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

不使用 async/await的语句Task.Factory.StartNew是不正确的,只是某些默认值可能不是您想要的常见情况(这是Task.Run引入原因的一部分)。

看:

于 2013-05-16T13:32:53.983 回答
4

不久前我遇到了同样的问题。我在这里贴了一篇关于它的小帖子:

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

在经历了很多挫折之后,我发现 usingawait Task.Factory.StartNew不能很好地与 await 配合使用。

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

基本上你需要使用Task.Run代替,因为await不能很好地与Task.Factory.StartNew

于 2013-05-16T11:09:20.280 回答
0

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

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

await/asycn 不能很好地与Task.Factory.StartNew().

只需替换Task.Factory.StartNewTask.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 还写了一篇关于它的简短博文。

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

于 2013-05-16T13:16:32.617 回答