我试图在不冻结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
答案 0 :(得分:4)
我刚才遇到了同样的问题。我发了一篇关于它的帖子here:
今天我有一个重要的头发拉动时刻。我在包含在新任务中的代码块上使用了await / async。无论我做了什么,它都会启动任务但不等待结果。
经过多次挫折之后,我发现使用
await Task.Factory.StartNew
并不能很好地等待。最后,我只是将其更改为Task.Run然后工作正常。
基本上您需要使用Task.Run,因为await
与Task.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。
很高兴获得有关此问题的更多信息,对我来说仍然很奇怪。