This article從SynchronizationContext
可ExecutionContext
流動狀態:Task.Run何時將SynchronizationContext與ExecutionContext一起使用?
private void button1_Click(object sender, EventArgs e) { button1.Text = await Task.Run(async delegate { string data = await DownloadAsync(); return Compute(data); }); }
這裏就是我的心智模型告訴我將與此代碼發生。 A 用戶單擊button1,導致UI框架在UI線程上調用button1_Click 。代碼然後啓動一個工作項目以在ThreadPool上運行(通過Task.Run)。該工作項目啓動一些下載工作 並異步等待它完成。然後,ThreadPool上的後續工作項目 會對該下載的結果執行一些計算密集型操作,並返回結果,導致在UI線程上等待完成的任務爲 。此時,線程處理此button1_Click方法的其餘部分,將計算結果存儲到button1的Text屬性中。
如果SynchronizationContext沒有作爲ExecutionContext的 部分流動,我的期望是有效的。如果它確實流通,但是,我會很難過 失望。 Task.Run在被調用時捕獲ExecutionContext,並且 使用它來運行傳遞給它的委託。這意味着當Task.Run被調用 時當前的SynchronizationContext將流入任務,並在調用 下載同步並等待結果任務時將成爲Current。這意味着,等待將看到當前同步上下文和發佈 剩餘的異步方法作爲延續在UI線程上運行。這意味着我的計算方法很可能是 在UI線程上運行,而不是在ThreadPool上運行,導致我的應用程序出現 響應問題。
現在的故事變得有點亂七八糟:ExecutionContext實際上有兩種捕捉方法,但是 只有其中一種是公開的。內部的一個(在mscorlib的內部) 是由大多數異步功能使用的一個mscorlib,它可以選擇允許調用者取消SynchronizationContext作爲ExecutionContext的一部分; 對應的,還有一個運行的內部過載,支持忽略存儲在ExecutionContext中的 的SynchronizationContext,實際上假裝沒有捕獲到一個 (這又是mscorlib中大多數功能所使用的重載)。 這意味着的是,幾乎所有的異步操作,其核心 執行駐留在mscorlib中不會流 的SynchronizationContext作爲的ExecutionContext的一部分,但任何 異步操作,其核心執行駐留其他任何地方 將流入的SynchronizationContext作爲的ExecutionContext的一部分。前面提到,異步方法的「構建器」是負責在異步方法中流動ExecutionContext的 類型,而這些構建器確實存在於mscorlib中,並且它們確實使用內部的 重載......因此,SynchronizationContext不會作爲部分 跨越等待的ExecutionContext(這又是與任務 等待者支持捕獲SynchronizationContext和Postinging 的方式分開的)。爲了幫助處理ExecutionContext執行的情況 flow SynchronizationContext,異步方法基礎架構嘗試 忽略由於流動而被設置爲Current的SynchronizationContexts。
但是,它並不完全清楚我當這可能發生。看來,它會發生在使用公衆ExecutionContext.Capture
方法和內部Task.Run
超載,以抑制流動SynchronizationContext
與ExecutionContext
是而不是使用,但我不知道什麼時候會。
在我的.NET 4.5 Task.Run
測試似乎並不與ExecutionContext
流動的SynchronizationContext
:
private async void button1_Click(object sender, EventArgs e) {
Console.WriteLine("Click context:" + SynchronizationContext.Current);
button1.Text = await Task.Run(async delegate {
// In my tests this always returns false
Console.WriteLine("SynchronizationContext was flowed: " + (SynchronizationContext.Current != null));
string data = await DownloadAsync();
return Compute(data);
});
}
所以我的問題是在什麼情況下會Compute()
在UI上下文中運行(阻塞UI線程)在文章中討論?