[英]await does not resume context after async operation?
我已經從Noseratio中讀到了這個問題 , 該問題顯示了一個行為,即在等待完成其操作后, TaskScheduler.Current
不同 。
答案指出:
如果沒有執行任何實際任務 ,則
TaskScheduler.Current
與TaskScheduler.Default
相同
這是真的。 我已在這里看到它:
TaskScheduler.Default
- 返回
ThreadPoolTaskScheduler
一個實例TaskScheduler.Current
- 如果從執行任務中調用,則返回當前正在執行的任務的
TaskScheduler
- 如果從任何其他地方調用將返回
TaskScheduler.Default
但轉念一想,如果是這樣,讓我們做創建一個實際的Task
(不只是Task.Yield()
並對其進行測試:
async void button1_Click_1(object sender, EventArgs e)
{
var ts = TaskScheduler.FromCurrentSynchronizationContext();
await Task.Factory.StartNew(async () =>
{
MessageBox.Show((TaskScheduler.Current == ts).ToString()); //True
await new WebClient().DownloadStringTaskAsync("http://www.google.com");
MessageBox.Show((TaskScheduler.Current == ts).ToString());//False
}, CancellationToken.None, TaskCreationOptions.None,ts).Unwrap();
}
第一個Messagebox是“True”,第二個是“False”
題:
如您所見,我確實創建了一個實際任務。
我可以理解為什么第一個MessageBox產生True
。 多數民眾贊成:
如果從執行任務中調用,則返回當前正在執行的任務的TaskScheduler
並且該任務確實具有ts
,即發送的TaskScheduler.FromCurrentSynchronizationContext()
但為什么在第二個 MessageBox中沒有保留上下文? 對我來說,斯蒂芬的回答並不清楚。
附加信息 :
如果我寫(第二個消息框):
MessageBox.Show((TaskScheduler.Current == TaskScheduler.Default).ToString());
它確實產生了true
。 但為什么 ?
混淆的原因是:
TaskScheduler
。 在UI線程上運行的代碼的默認情況是TaskScheduler.Current
存儲ThreadPoolTaskScheduler
和SynchronizationContext.Current
存儲WindowsFormsSynchronizationContext
(或其他UI應用程序中的相關文件) TaskScheduler.Current
中的ThreadPoolTaskScheduler
並不一定意味着它是用於運行當前代碼段的TaskScheduler
。 它還意味着TaskSchdeuler.Current == TaskScheduler.Default
,因此“沒有使用TaskScheduler
” 。 TaskScheduler.FromCurrentSynchronizationContext()
不返回“acutal” TaskScheduler
。 它返回一個“代理”,可以將任務直接發布到捕獲的SynchronizationContext
。 因此,如果您在開始任務之前(或在任何其他地方)運行測試,您將獲得與等待之后相同的結果 :
MessageBox.Show(TaskScheduler.Current == TaskScheduler.FromCurrentSynchronizationContext()); // False
因為TaskScheduler.Current
是ThreadPoolTaskScheduler
而TaskScheduler.FromCurrentSynchronizationContext()
返回SynchronizationContextTaskScheduler
。
這是你的例子的流程:
SynchronizationContextTaskScheduler
從UI的SynchronizationContext
(即WindowsFormsSynchronizationContext
)。 TaskScheduler
上使用Task.Factory.StartNew
計划您創建的任務。 由於它只是一個“代理”,它將委托發布到WindowsFormsSynchronizationContext
,后者在UI線程上調用它。 SynchronizationContextTaskScheduler
相關聯。 WindowsFormsSynchronizationContext
時被“掛起”。 WindowsFormsSynchronizationContext
而不是SynchronizationContextTaskScheduler
因為SynchronizationContext
具有優先權( 這可以在Task.SetContinuationForAwait
看到 )。 然后它在UI線程上定期運行,沒有任何“特殊” TaskScheduler
因此TaskScheduler.Current == TaskScheduler.Default
。 因此,創建的任務在使用SynchronizationContext
的代理TaskScheduler
上運行,但是在await發布到SynchronizationContext
而不是TaskScheduler
之后的延續。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.