bit*_*onk 7 .net c# async-await c#-5.0
在使用时await,默认情况下SynchronizationContext捕获(如果存在)并且await使用该上下文执行(继续块)之后的代码块(这导致线程上下文切换).
public async Task DoSomethingAsync()
{
// We are on a thread that has a SynchronizationContext here.
await DoSomethingElseAsync();
// We are back on the same thread as before here
//(well sometimes, depending on how the captured SynchronizationContext is implemented)
}
Run Code Online (Sandbox Code Playgroud)
虽然此默认值可能在您希望在异步操作完成后返回UI线程的UI上下文中有意义,但它似乎没有意义作为大多数其他方案的默认值.对于内部库代码来说当然没有意义,因为
在我看来,微软已经决定了错误的默认值.
现在我的问题:
有没有其他(最好是更好的)方法来解决这个问题,而不是混淆await我的代码中的所有调用.ConfigureAwait(false)?这很容易忘记,使代码可读性降低.
更新:await Task.Yield().ConfigureAwait(false);在每个方法的开头
调用是否足够?如果这可以保证我将在一个没有SynchronizationContextaferwards 的线程上,所有后续await调用都不会捕获任何上下文.
首先,await Task.Yield().ConfigureAwait(false)不会工作,因为Yield不返回Task. 还有其他方法可以跳转到池线程,但也不推荐使用它们,请检查“为什么 \xe2\x80\x9cSwitchTo\xe2\x80\x9d 从异步 CTP/发布中删除?”
如果您仍然想这样做,这里有一个很好的技巧,利用这样一个事实:如果原始线程上有同步上下文,ConfigureAwait(false) 则将延续推送到池线程,即使这里没有异步:
static Task SwitchAsync()\n{\n if (SynchronizationContext.Current == null)\n return Task.FromResult(false); // optimize\n\n var tcs = new TaskCompletionSource<bool>();\n Func<Task> yield = async () =>\n await tcs.Task.ConfigureAwait(false);\n var task = yield();\n tcs.SetResult(false);\n return task;\n}\n\n// ...\n\npublic async Task DoSomethingAsync()\n{\n // We are on a thread that has a SynchronizationContext here.\n await SwitchAsync().ConfigureAwait(false); \n\n // We\'re on a thread pool thread without a SynchronizationContext \n await DoSomethingElseAsync(); // no need for ConfigureAwait(false) here\n // ... \n}\nRun Code Online (Sandbox Code Playgroud)\n\n再说一遍,这不是我自己会广泛使用的东西。我对使用也有类似的担忧ConfigureAwait(false)。一个结果是,虽然ConfigureAwait(false)可能不是普遍完美,但await只要您不关心同步上下文,就使用它是可行的方法。这是 .NET 源代码本身密切遵循的准则。
另一个结果是,如果您担心其中的第三方代码DoSomethingElseAsync可能无法ConfigureAwait(false)正确使用,只需执行以下操作:
public async Task DoSomethingAsync()\n{\n // We are on a thread that has a SynchronizationContext here.\n await Task.Run(() => DoSomethingElseAsync()).ConfigureAwait(false);\n\n // We\'re on a thread pool thread without a SynchronizationContext \n await DoYetSomethingElseAsync(); // no need for ConfigureAwait(false) here\n // ... \n}\nRun Code Online (Sandbox Code Playgroud)\n\n这将使用Task.Run接受Func<Task>lambda 的重写,在池线程上运行它并返回一个未包装的任务。您只需在第一个awaitinside时执行此操作DoSomethingAsync。潜在成本与:一个额外的线程切换相同SwitchAsync,但代码更具可读性且结构更好。这是我在工作中使用的方法。
| 归档时间: |
|
| 查看次数: |
692 次 |
| 最近记录: |