等待Task.WhenAll()似乎是死锁

问题描述 投票:-1回答:1

在以下代码中,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测试尝试通过调用异步方法异步创建测试数据,该异步方法本身是awaits来自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()

我想了解为什么在使用qazxsw poi时发生了死锁。

编辑:添加锁定线程的调用堆栈

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()
c# async-await task
1个回答
1
投票

(结论从评论中总结,对于任何未来的观众)。

你没有在任何地方阻止,所以我能想到的唯一可能的解释是至少有一个请求没有完成。

(如果你正在等待Task.WhenAll()完成,那么我很可能会遇到死锁,因为你没有使用Task,但是因为你只有ConfigureAwait(false)你的任务,我很确定这不是原因)。

鉴于您的请求在单独运行时成功完成,这意味着当并行运行多个请求时可能存在一些并发问题,可能与await无关,或者与请求发出的服务器有关(如果他们正在对一个真正的服务器运行)。

鉴于您的任务列表没有显示任何有趣的内容,我倾向于认为其中一个请求已同步阻止调用它的线程。

只需查看其中一个请求是否已同步阻止。打开“线程”窗口,依次双击每个线程。大多数人不会做任何事情,但至少有一个人可能正在运行你的代码,或运行一个从你的代码调用的方法。查看调用堆栈以尝试查找正在发生的事情。您可以双击调用堆栈中的条目以检查每个点的范围内的变量。

© www.soinside.com 2019 - 2024. All rights reserved.