[英]Why doesn't my Task.ContinueWith execute in .NET 4.5?
請考慮以下代碼
Task<T>.Factory.StartNew(() =>
{
// block #1: load some data from local file cache
}
)
.ContinueWith(task =>
{
// block #2: handle success or failure of load-from-cache operation and surface to application
},
cancellationToken,
TaskContinuationOptions.NotOnCanceled,
TaskScheduler.FromCurrentSynchronizationContext()
)
.ContinueWith(task =>
{
// block #3: load data from remote data source
},
TaskContinuationOptions.NotOnCanceled
);
在.NET 4.0中,此代碼按預期執行:第一個塊在后台線程中運行,然后第二個塊運行,最后第三個塊運行。
但是,在.NET 4.5中,無論第一個塊發生了什么(成功,故障或取消),第二個塊都不會運行。 並且第三個塊也不運行,等待非啟動的第二個塊。
此代碼位於WPF應用程序中。 它在應用程序初始化期間運行,加載應用程序啟動所需的一些數據。 在主線程(我稱之為異步代碼)中,我正在等待從代碼塊#3填充結果,然后再繼續。 如果遠程數據調用超時,則將繼續初始化來自塊#1(緩存)的數據。
在這兩個版本的.Net中,我們遇到了ContinueWith和TaskScheduler屬性Current和Default的設計問題
在.Net 4.0中,TaskScheduler的Current和Default都具有相同的值,即ThreadPoolTaskScheduler ,它是ThreadPool的上下文調度程序,它不是更新UI的那個,即SynchronizationContextTaskScheduler ,這就是你的代碼在.Net 4.0中正常運行的原因。
在.Net 4.5中,事情發生了變化。 所以,當你說TaskScheduler.Current和TaskScheduler.Default然后你會得到兩個不同的調度程序(在你的情況下WPF時)
Current is = SynchronizationContextTaskScheduler
默認是= ThreadPoolTaskScheduler
現在回到你的問題,當你使用ContinueWith選項時,它具有調度程序的硬編碼值作為TaskScheduler.Current。 具體來說,在WPF和Asp.net中,SynchronizationContextTaskScheduler意味着它是UI線程同步上下文,一旦被阻止,在執行當前執行線程並在UI線程上下文中運行之前,其他任何內容都不會執行。
建議(.Net 4.5): 嘗試在ContiueWith中傳遞TaskScheduler.Default(NON UI Scheduler)或避免使用ContinueWith,而是以排隊方式加入任務。
我希望這能清楚地說明行為正在發生變化的原因。 有關更多詳細信息,請參閱此討論: 為什么TaskScheduler.Current是默認的TaskScheduler?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.