在以下代码中,Task.WhenAll
行上发生死锁:
[Fact]
public async Task GetLdapEntries_ReturnsLdapEntries()
{
var ldapEntries = _fixture.CreateMany<LdapEntryDto>(2).ToList();
var creationTasks = new List<Task>();
foreach (var led in ldapEntries)
{
var task = _attributesServiceClient.CreateLdapEntry(led);
creationTasks.Add(task);
}
await Task.WhenAll(creationTasks); // <- deadlock here
var result = await _ldapAccess.GetLdapEntries();
result.Should().BeEquivalentTo(ldapEntries);
}
public async Task<LdapEntryDto> CreateLdapEntry(LdapEntryDto ldapEntryDto)
{
using (var creationResponse = await _httpClient.PostAsJsonAsync<LdapEntryDto>("", ldapEntryDto))
{
if (creationResponse.StatusCode == HttpStatusCode.Created)
{
return await creationResponse.Content.ReadAsAsync<LdapEntryDto>();
}
return null;
}
}
xUnit测试试图通过调用本身await
来自Web服务的响应的异步方法来异步创建测试数据。 _httpClient
是通过HttpClient
在内存TestServer
中创建的真实TestServer.CreateClient()
。
在using line
方法中的CreateLdapEntry
上设置断点时,将命中两次。永远不会命中状态代码检查的断点。在断开Task.WhenAll()
并检查creationTasks
时,两个任务都处于状态WaitingForActivation
:
creationTasks
Count = 2
[0]: Id = 32, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}"
[1]: Id = 33, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}"
当不使用Task.WhenAll()
而是分别等待每个任务时,不会发生死锁:
foreach (var led in ldapEntries)
{
await _attributesServiceClient.CreateLdapEntry(led);
}
我知道有人问过similar question,但是那里的代码示例使用的是.Result
,而不是await Task.WhenAll()
。
我想了解为什么在使用Task.WhenAll()
时会发生死锁。
编辑:添加了锁定线程的调用堆栈
Not Flagged 3992 11 Worker Thread Worker Thread Microsoft.AspNetCore.Routing.dll!Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke [Managed to Native Transition] Microsoft.AspNetCore.Routing.dll!Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext httpContext) ShibbolethAttributes.Service.dll!RoleManager.Service.Middleware.ApiKeyHandlerMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext context) Line 38 Microsoft.AspNetCore.Diagnostics.dll!Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext context) System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Startd__7>(ref Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.d__7 stateMachine) Microsoft.AspNetCore.Diagnostics.dll!Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext context) Microsoft.AspNetCore.Hosting.dll!Microsoft.AspNetCore.Hosting.Internal.HostingApplication.ProcessRequestAsync(Microsoft.AspNetCore.Hosting.Internal.HostingApplication.Context context) Microsoft.AspNetCore.TestHost.dll!Microsoft.AspNetCore.TestHost.TestServer.ApplicationWrapper.ProcessRequestAsync(Microsoft.AspNetCore.Hosting.Internal.HostingApplication.Context context) Microsoft.AspNetCore.TestHost.dll!Microsoft.AspNetCore.TestHost.HttpContextBuilder.SendAsync.AnonymousMethod__0() System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Startc__DisplayClass10_0.b__0>d stateMachine) Microsoft.AspNetCore.TestHost.dll!Microsoft.AspNetCore.TestHost.HttpContextBuilder.SendAsync.AnonymousMethod__0() System.Private.CoreLib.dll!System.Threading.Tasks.Task.InnerInvoke() System.Private.CoreLib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) System.Private.CoreLib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot) System.Private.CoreLib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch() Not Flagged 1496 10 Worker Thread Worker Thread Microsoft.AspNetCore.Routing.dll!Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke Microsoft.AspNetCore.Routing.dll!Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext httpContext) ShibbolethAttributes.Service.dll!RoleManager.Service.Middleware.ApiKeyHandlerMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext context) Line 38 Microsoft.AspNetCore.Diagnostics.dll!Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext context) System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Startd__7>(ref Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.d__7 stateMachine) Microsoft.AspNetCore.Diagnostics.dll!Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext context) Microsoft.AspNetCore.Hosting.dll!Microsoft.AspNetCore.Hosting.Internal.HostingApplication.ProcessRequestAsync(Microsoft.AspNetCore.Hosting.Internal.HostingApplication.Context context) Microsoft.AspNetCore.TestHost.dll!Microsoft.AspNetCore.TestHost.TestServer.ApplicationWrapper.ProcessRequestAsync(Microsoft.AspNetCore.Hosting.Internal.HostingApplication.Context context) Microsoft.AspNetCore.TestHost.dll!Microsoft.AspNetCore.TestHost.HttpContextBuilder.SendAsync.AnonymousMethod__0() System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Startc__DisplayClass10_0.b__0>d stateMachine) Microsoft.AspNetCore.TestHost.dll!Microsoft.AspNetCore.TestHost.HttpContextBuilder.SendAsync.AnonymousMethod__0() System.Private.CoreLib.dll!System.Threading.Tasks.Task.InnerInvoke() System.Private.CoreLib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) System.Private.CoreLib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot) System.Private.CoreLib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch()
答案 0 :(得分:1)
(结论总结,针对以后的任何观看者)。
您没有在任何地方进行阻止,因此我能想到的唯一可能的解释是,至少有一个请求没有完成。
(如果您正在同步等待Task
完成,那么我很可能会陷入僵局,因为您没有使用ConfigureAwait(false)
,但是因为您只await
个任务,我很确定这不是原因)。
鉴于您的请求在单独运行时成功完成,这意味着在并行运行多个请求时可能存在一些并发问题,这可能与_httpClient
或服务器有关请求是针对(如果它们是针对真实服务器运行的)。
鉴于您的“任务”列表没有显示任何有趣的内容,我倾向于认为其中一个请求已同步阻止了调用该线程的线程。
仅查看其中一个请求是否已被同步阻止。打开“线程”窗口,然后依次双击每个线程。大多数不会做任何事情,但是至少有一个可能正在运行您的代码,或者正在运行从您的代码中调用的方法。查看调用堆栈以尝试了解发生了什么。您可以双击调用堆栈中的条目以在每个点检查作用域中的变量。