[英]ConfigureAwait(False) doesn't change context after ContinueWith()
[英]ConfigureAwait(false) when using ContinueWith
什么相當於使用:
await task.ConfigureAwait(false);
當使用像這樣的continuation(不使用C#編譯器的async/await
轉換)?
var taskOfString = ScheduleWorkOnThreadPoolAsync();
// I'd like this continuation to not have to
// "flow" the synchronization context but to simply
// execute wherever it can, i.e. I'd like to tell is
// ConfigureAwait(false) for its previous task.
// How do I do that?
taskOfString.ContinueWith(t => { });
public async Task<string> ScheduleWorkOnThreadPoolAsync()
{
return Task.Run(() => return "Foo" );
}
我假設什么都不做 ,即只是保持原樣相當於調用ConfigureAwait(false)
,這也是我在調試代碼時看到的情況。 它可以在任何線程上跳躍。
只有當我們想要指定調度程序或同步上下文來運行延續時,我們才需要將額外的信息傳遞給接受TaskScheduler
的重載。 否則,默認運行時不考慮執行上下文。
但是,如果我錯了,我還是要求確認或更正。
當使用像這樣的continuation(不使用C#編譯器的async / await轉換)?
你應該幾乎總是使用async
/ await
。 它們具有更安全的默認行為。 ContinueWith
是一個危險的低級API。
我假設什么也不做,即只是將其保留原樣等同於調用ConfigureAwait(false)...只有當我們想要指定調度程序或同步上下文來運行繼續時我們需要傳遞額外的信息到接受TaskScheduler的重載。 否則,默認運行時不考慮執行上下文。
不。這是不正確的,雖然簡單的測試不會揭示問題。
正如我在我的博客文章描述的,為什么你不應該使用ContinueWith
,默認TaskScheduler
的ContinueWith
不 TaskScheduler.Default
。 這是TaskScheduler.Current
。 由於這在每個場景中都很混亂,因此您應該始終將TaskScheduler
傳遞給ContinueWith
和StartNew
。
如果要await x.ConfigureAwait(false)
行為,您實際上會執行以下操作:
var continuation = x.ContinueWith(callback, CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.DenyChildAttach,
TaskScheduler.Default);
TaskContinuationOptions.ExecuteSynchronously
模擬await
的同步 - 如果可能的行為 。 如果附加了延續任務, TaskContinuationOptions.DenyChildAttach
可以防止出現問題(當使用AttachedToParent
將子任務附加到它們時,用於異步的任務會產生令人驚訝的行為)。 TaskScheduler.Default
模擬始終在線程池上下文上執行的ConfigureAwait(false)
行為。
作為最后一點,你可能需要對continuation
做一些事情 - 至少要觀察異常並以某種方式處理它們。
在這一點上,我應該清楚為什么我建議await
。 在最壞的情況下,你只需要添加一個輔助方法來使用await
而不是ContinueWith
- await
更加可維護,IMO。
我已經研究過的參考源Task
,然后ConfiguredTaskAwaitable
通過GetAwaiter.OnCompleted
背透入Task.SetContinuationForAwait
(與continueOnCapturedContext
為false
),並且將其放入到:
if (!AddTaskContinuation(tc, addBeforeOthers: false))
tc.Run(this, bCanInlineContinuationTask: false);
這基本上就是ContinueWith
。 所以:是的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.