2013-05-16 13 views
3

我試圖在不凍結GUI線程的情況下執行一些耗時的操作。 UpdateSomething方法在我的ViewModel的構造函數中一次調用兩次,並且一次單擊按鈕(RelayCommand)。如果方法是通過RelayCommand調用的,則該方法在WorkerThread中執行,但在方法調用來自構造函數時在MainThread(GUI)中運行。AsyncAwait會導致意想不到的方法行爲,如果從構造函數中調用方法,則會在錯誤的線程中運行

這是什麼原因導致奇怪行爲?我通過IntelliTrace進行了幾次檢查。

這是有問題的方法:

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

我使用WPF和.NET 4.5

+1

能否請您解釋與您添加解決方案的答案?這可能對其他人也有幫助:) –

+0

用戶@ Rene147回答了這個問題,我將他的答案標記爲正確答案。不幸的是,由於某些原因我不知道他刪除了他的答案。 – Joel

+1

您應該閱讀以下內容:http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx –

回答

4

。對於其中Task的行動在主線程上運行的情況下,最有可能的原因是,該方法UpdateSomething正在從內另一Task(即原定在主線程上運行Task)進行調用。在這種情況下,TaskScheduler.Current是主線程TaskScheduler而不是TaskScheduler.Default,它將隊列工作到線程池。

Task.Factory.StartNew默認爲使用TaskScheduler.Current(您可以通過調用適當的覆蓋來更改它的用途),而Task.Run使用TaskScheduler.Default

Task.Factory.StartNew不會播放與異步/ await不正確的聲明,只是一些默認值可能不是您想要的常見情況(這是爲什麼Task.Run被引入的原因的一部分)。

請參見:

4

我剛纔碰到了同樣的問題。我卡住了一個小帖子關於它here

今天我有一個主要的頭髮拉片刻。我在一個包含在新任務中的代碼塊上使用了await/async。不管我做了什麼,它只是開始任務,但不等待結果。

在經歷了很多挫折之後,我發現使用await Task.Factory.StartNew並不能很好地與等待。

最後我簡單地將它改爲Task.Run然後什麼工作得很好。

基本上你需要使用Task.Run而不是因爲awaitTask.Factory.StartNew

+0

有關這些差異的解釋,參見['Task.Run' vs'Task.Factory.StartNew'](http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx)。 –

0

對此問題予以@ Rene147回答發揮很好,但他刪除了他的答案。 (無論何種原因)

我將簡要地改寫他寫的東西:

等待/ asycn不Task.Factory.StartNew()得到很好的發揮。

只需更換由Task.RunTask.Factory.StartNew,一切都應該工作:

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了。

很高興能獲得關於這個問題的更多信息,對我來說仍然很奇怪。

+1

版主刪除了Rene的回答...我猜這是因爲有人將其標記爲僅鏈接回覆或垃圾郵件,所以我編輯了答案,將鏈接中的內容移動到答案中,並標記了它被取消刪除。主持人真的不應該刪除有用的,積極的,並接受問題的答案,特別是當他們是唯一的答案時,他們實際上回答了這個問題。 – Rachel

相關問題