2013-10-23 15 views
2

This articleSynchronizationContextExecutionContext流動狀態: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超載,以抑制流動SynchronizationContextExecutionContext而不是使用,但我不知道什麼時候會。

在我的.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線程)在文章中討論?

回答

6

什麼時候Task.Run流的SynchronizationContext與執行上下文?

從來沒有。

該文章的要點是流動ExecutionContext的公共API將流入SynchronizationContext。但是Task.Run(以及「幾乎任何其核心實現駐留在mscorlib中的異步操作」)都不會這樣做。

以「我的期望是有效的」開始的段落如果是假設的。他正在描述如果Task.Run使用公共API流動ExecutionContext會發生。這導致問題如果它做到了這一點。這就是爲什麼它不會這樣做。

相關問題