我在GitHub上偶然发现了一个问题(https://github.com/HTBox/allReady/issues/1313),在那里他们讨论了如何ConfigureAwait(false)在ASP.NET核心中删除代码
呼叫
ConfigureAwait(false)是多余的,什么都不做
我能找到的最好的答案是一个"旁注"(来自Stephen Cleary,https: //stackoverflow.com/a/40220190/2805831 )
ASP.NET Core不再具有"上下文"
那么,ASP.NET Core中ConfigureAwait(false)真的没必要(即使使用完整的.Net Framework)?在某些情况下,它在性能方面是否有任何实际的好处,或者在结果/语义上有所不同?
编辑:如果我将其作为控制台应用程序托管或在IIS中,它在这方面有所不同吗?
从我在线阅读的内容来看,安全性(线程主体),文化等上下文相关的项目应该跨越执行工作单元的边界内的异步线程.
我遇到了非常混乱和潜在危险的错误.我注意到我的线程的CurrentPrincipal在异步执行中丢失了.
以下是ASP.NET Web API方案的示例:
首先,让我们设置一个简单的Web API配置,其中包含两个委托处理程序,用于测试目的.
他们所做的就是写出调试信息并传递请求/响应,除了第一个"DummyHandler",它设置线程的主体以及要在整个上下文中共享的一段数据(请求的相关ID).
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MessageHandlers.Add(new DummyHandler());
config.MessageHandlers.Add(new AnotherDummyHandler());
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
public class DummyHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
CallContext.LogicalSetData("rcid", request.GetCorrelationId());
Thread.CurrentPrincipal = new ClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new[]{ new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "dgdev") }, "myauthisthebest")));
Debug.WriteLine("Dummy Handler Thread: {0}", Thread.CurrentThread.ManagedThreadId);
Debug.WriteLine("User: {0}", (Object)Thread.CurrentPrincipal.Identity.Name);
Debug.WriteLine("RCID: {0}", CallContext.LogicalGetData("rcid"));
return base.SendAsync(request, cancellationToken) …Run Code Online (Sandbox Code Playgroud) 它建议使用一个ConfigureAwait(false)当你可以随时,特别是在图书馆,因为它可以帮助避免死锁和提高性能.
我编写了一个大量使用异步的库(访问数据库的Web服务).图书馆的用户遇到了僵局,经过多次痛苦的调试和修补后,我将其追踪到了单独使用await Task.Yield().我使用过的其他任何地方.ConfigureAwait(false),但是不支持Task.Yield().
对于需要等效的情况,推荐的解决方案是Task.Yield().ConfigureAwait(false)什么?
我已经读过有关如何SwitchTo移除某个方法的内容.我可以看出为什么那可能是危险的,但为什么没有相应的Task.Yield().ConfigureAwait(false)?
编辑:
为了提供我的问题的进一步背景,这里有一些代码.我正在实现一个开源库,用于访问支持异步的DynamoDB(作为AWS的服务的分布式数据库).IX-Async库IAsyncEnumerable<T>提供了许多操作返回.该库不提供从以"块"提供行的数据源生成异步枚举的好方法,即每个异步请求返回许多项.所以我有自己的通用类型.该库支持预读选项,允许用户指定在调用实际需要之前应该请求多少数据.MoveNext()
基本上,这是如何工作的,我通过调用GetMore()和传递这些块之间的状态来请求块.我将这些任务放入chunks队列并将它们出列并将它们转换为我放在单独队列中的实际结果.这个NextChunk()方法就是问题所在.根据值的不同,ReadAhead我会在完成最后一个(最多)之后保持获取下一个块,直到需要一个值但不可用(无)或仅获取超出当前使用值的下一个块(一些).因此,获取下一个块应该并行/不阻止获取下一个值.枚举器代码是:
private class ChunkedAsyncEnumerator<TState, TResult> : IAsyncEnumerator<TResult>
{
private readonly ChunkedAsyncEnumerable<TState, TResult> enumerable;
private readonly ConcurrentQueue<Task<TState>> chunks = new ConcurrentQueue<Task<TState>>();
private readonly Queue<TResult> results = new Queue<TResult>();
private CancellationTokenSource cts = new CancellationTokenSource();
private TState lastState;
private TResult current;
private …Run Code Online (Sandbox Code Playgroud)