2015-05-21 40 views
0

實施例:由於垃圾回收,可以調用Task.GetAwaiter()。OnCompleted()失敗嗎?

var task = Task.Factory.StartNew(() => 
{ 
    Thread.Sleep(1000); 
    throw new Exception("fault!"); 
}); 

task.GetAwaiter().OnCompleted(() => 
{ 
    if (task.IsFaulted) 
    { 
    Console.WriteLine(task.Exception); 
    } 
}); 

上面的代碼等待使用TaskAwaiter任務完成。我在整個網絡的幾個例子中看到了類似這樣的代碼,可以使用OnCompleted或使用GetResult

爲了使回調正常工作,是否需要明確地保留對awaiter的引用?換句話說,如果在任務結束之前收集器被垃圾收集,這是一個問題嗎?

+4

'我在整個網絡的幾個例子中都看到了類似這樣的代碼,無論是用OnCompleted還是用GetResult.Wow,我當然希望不要;這是一個*可怕的*模式!正如彼得所指出的那樣,如果必須的話,「等待」要遠遠優越 - 甚至是「ContinueWith」。哦,'Task.Run'>'StartNew'和'Task.Exception'會給你一個'AggregateException'而不是你想要的。是的,幾乎所有關於這個代碼片段的東西都不是最理想的。 –

+0

感謝您的反饋!我最終重構了我的設計,並且隨處使用異步/等待更清晰。我不得不繼續使用StartNew,只是因爲它似乎是指定'TaskCreationOptions.LongRunning'的唯一方法,我確實需要它。 – glopes

+0

正如我在我的博客上解釋的,[你可能不需要'LongRunning'](線程池調整)(http://blog.stephencleary.com/2013/08/startnew-is-dangerous.html)在500毫秒內如果你*不通過它。如果你決定保留'StartNew',**一定要明確指定一個調度器**以及'DenyChildAttach'標誌。 –

回答

0

總之,經過對所有答案和評論的讚賞之後,我關於使用GetAwaiter()的實現是:不要做

如果你需要它,這很可能表明你的異步設計非常需要重構。

3

是否有必要明確地保留對awaiter的引用以便回調起作用?換句話說,如果在任務結束之前收集器被垃圾收集,這是一個問題嗎?

我不明白怎麼可能。這可能是一個問題的唯一方法是如果需要使用awaiter對象。但是爲了嘗試這樣做,它必須有一個對awaiter對象的引用。但是如果它有一個對awaiter對象的引用,該對象將不會被垃圾收集。

這就是說,你爲什麼要以這種方式實施延續?通常情況下,您只需使用await並在撥打await之後用相同的方法編寫延續。即使在由於某種原因而不起作用的情況下(例如,不在async方法中),您通常也會使用ContinueWith()方法。

你爲什麼打電話GetAwaiter()?聽起來你可能會從你的問題中提供更多的細節中受益,因此可以提供滿足你更廣泛需求的答案(或者你可以問第二個問題來徵求關於這方面的建議)。

+0

大家都在指出這是一種設計氣味。我想出了一個好得多的解決方案來解決這個問題,這個問題涉及到重構架構以在任何地方使用異步/等待,並且我不得不承認最終它更簡單和更強大。感謝您的反饋!我會回答我自己的問題,以便更直白地說出這一點。 – glopes