Entity Framework 使用 "one-to-many" 关系和 WebApi 时的核心 async/wait 死锁

Entity Framework Core async/wait deadlock when using "one-to-many" relationship and WebApi

我在使用 EF Core 提供程序的异步实现时遇到死锁。

假设我有以下型号:

public class Player
{
    public string PlayerId { get; set;}

    public string Name { get; set;}

    public List<Game> Games { get; set;}
}

public class Game
{
    public string GameId { get; set; }

    public string PlayerId { get; set; }
    public Player Player { get; set;}
}

现在我想运行下面的查询:

ctx.Players
.Include(p => p.Games)
.Where(p => p.PlayerId == "123")
.Select(p => new {
    PlayerId = p.PlayerId,
    Games = p.Games.ToList()
}).ToListAsync();

当我 运行 通过控制台 Application/XUnit 测试此代码时,它正常工作... 但是当我通过 ASP.Net WebApi 运行 它进入死锁并且永远不会结束...

我一直使用 ConfigureAwait(false) 以防止出现此类情况,但似乎有问题的代码在下面。 我认为它可能在 EFCore 使用的 System.Interactive.Async 库下 - 更具体地说,它在:https://github.com/Reactive-Extensions/Rx.NET/blob/develop/Ix.NET/Source/System.Interactive.Async/ToAsyncEnumerable.cs#L72 调用“Result”实际上阻塞了执行线程。

有没有人遇到过这种行为,也许有一些解决方法?

请注意,如果我不加载“游戏”实体,那么一切也都正常...

编辑:添加了 StackTrace:(参见对 ToEnumerable 的调用)

Not Flagged 21672   5   Worker Thread   grpc 0 (cq 0) System.Interactive.Async.dll!System.Linq.AsyncEnumerable.**ToEnumerable_**<NG.Admin.BL.DAL.Entities.Game> Normal
mscorlib.dll!System.Threading.Monitor.Wait(object obj, int millisecondsTimeout, bool exitContext)
mscorlib.dll!System.Threading.Monitor.Wait(object obj, int millisecondsTimeout)
mscorlib.dll!System.Threading.ManualResetEventSlim.Wait(int millisecondsTimeout, System.Threading.CancellationToken cancellationToken)
mscorlib.dll!System.Threading.Tasks.Task.SpinThenBlockingWait(int millisecondsTimeout, System.Threading.CancellationToken cancellationToken)
mscorlib.dll!System.Threading.Tasks.Task.InternalWait(int millisecondsTimeout, System.Threading.CancellationToken cancellationToken)
mscorlib.dll!System.Threading.Tasks.Task.GetResultCore(bool waitCompletionNotification)
mscorlib.dll!System.Threading.Tasks.Task.Result.get()
System.Interactive.Async.dll!System.Linq.AsyncEnumerable.ToEnumerable_<NG.Admin.BL.DAL.Entities.Game>(System.Collections.Generic.IAsyncEnumerable<NG.Admin.BL.DAL.Entities.Game> source)
mscorlib.dll!System.Collections.Generic.List<NG.Admin.BL.DAL.Entities.Game>.List(System.Collections.Generic.IEnumerable<NG.Admin.BL.DAL.Entities.Game> collection)
System.Core.dll!System.Linq.Enumerable.ToList<NG.Admin.BL.DAL.Entities.Game>(System.Collections.Generic.IEnumerable<NG.Admin.BL.DAL.Entities.Game> source)
[Lightweight Function]
Microsoft.EntityFrameworkCore.dll!Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.SelectAsyncEnumerable<Microsoft.EntityFrameworkCore.Storage.ValueBuffer, NG.Admin.BL.Api.Player>.SelectAsyncEnumerator.MoveNext(System.Threading.CancellationToken cancellationToken)
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.OutputAsyncCausalityEvents.AnonymousMethod__0()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.OutputWaitEtwEvents.AnonymousMethod__0()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
mscorlib.dll!System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action action, bool allowInlining, ref System.Threading.Tasks.Task currentTask)
mscorlib.dll!System.Threading.Tasks.Task.FinishContinuations()
mscorlib.dll!System.Threading.Tasks.Task.FinishStageThree()
mscorlib.dll!System.Threading.Tasks.Task.TrySetResult(bool result)
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult(bool result)
NG.Data.Spanner.EF.dll!NG.Data.Spanner.EF.Query.Internal.SpannerAsyncQueryingEnumerable<Microsoft.EntityFrameworkCore.Storage.ValueBuffer>.SpannerAsyncEnumerator.MoveNext(System.Threading.CancellationToken cancellationToken) Line 55
[Resuming Async Method]
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.OutputAsyncCausalityEvents.AnonymousMethod__0()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.OutputWaitEtwEvents.AnonymousMethod__0()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
mscorlib.dll!System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action action, bool allowInlining, ref System.Threading.Tasks.Task currentTask)
mscorlib.dll!System.Threading.Tasks.Task.FinishContinuations()
mscorlib.dll!System.Threading.Tasks.Task.FinishStageThree()
mscorlib.dll!System.Threading.Tasks.Task.TrySetResult(bool result)
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult(bool result)
Microsoft.EntityFrameworkCore.dll!Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.SelectAsyncEnumerable<Microsoft.EntityFrameworkCore.Storage.ValueBuffer, Microsoft.EntityFrameworkCore.Storage.ValueBuffer>.SelectAsyncEnumerator.MoveNext(System.Threading.CancellationToken cancellationToken)
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.OutputAsyncCausalityEvents.AnonymousMethod__0()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.OutputWaitEtwEvents.AnonymousMethod__0()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
mscorlib.dll!System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action action, bool allowInlining, ref System.Threading.Tasks.Task currentTask)
mscorlib.dll!System.Threading.Tasks.Task.FinishContinuations()
mscorlib.dll!System.Threading.Tasks.Task.FinishStageThree()
mscorlib.dll!System.Threading.Tasks.Task.TrySetResult(bool result)
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult(bool result)
Microsoft.EntityFrameworkCore.Relational.dll!Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable.AsyncEnumerator.MoveNext(System.Threading.CancellationToken cancellationToken)
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.OutputAsyncCausalityEvents.AnonymousMethod__0()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.OutputWaitEtwEvents.AnonymousMethod__0()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
mscorlib.dll!System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action action, bool allowInlining, ref System.Threading.Tasks.Task currentTask)
mscorlib.dll!System.Threading.Tasks.Task.FinishContinuations()
mscorlib.dll!System.Threading.Tasks.Task.FinishStageThree()
mscorlib.dll!System.Threading.Tasks.Task.TrySetResult(bool result)
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult(bool result)
Microsoft.EntityFrameworkCore.Relational.dll!Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable.AsyncEnumerator.BufferlessMoveNext(bool buffer, System.Threading.CancellationToken cancellationToken)
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.OutputAsyncCausalityEvents.AnonymousMethod__0()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.OutputWaitEtwEvents.AnonymousMethod__0()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
mscorlib.dll!System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action action, bool allowInlining, ref System.Threading.Tasks.Task currentTask)
mscorlib.dll!System.Threading.Tasks.Task.FinishContinuations()
mscorlib.dll!System.Threading.Tasks.Task.FinishStageThree()
mscorlib.dll!System.Threading.Tasks.Task<System.__Canon>.TrySetResult(System.__Canon result)
mscorlib.dll!System.Threading.Tasks.TaskCompletionSource<System.__Canon>.TrySetResult(System.__Canon result)
Microsoft.EntityFrameworkCore.Relational.dll!System.Threading.Tasks.TaskExtensions.Cast.AnonymousMethod__0(System.Threading.Tasks.Task t)
mscorlib.dll!System.Threading.Tasks.ContinuationTaskFromResultTask.InnerInvoke()
mscorlib.dll!System.Threading.Tasks.Task.Execute()
mscorlib.dll!System.Threading.Tasks.Task.ExecutionContextCallback(object obj)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot)
mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution)
mscorlib.dll!System.Threading.Tasks.ThreadPoolTaskScheduler.TryExecuteTaskInline(System.Threading.Tasks.Task task, bool taskWasPreviouslyQueued)
mscorlib.dll!System.Threading.Tasks.TaskScheduler.TryRunInline(System.Threading.Tasks.Task task, bool taskWasPreviouslyQueued)
mscorlib.dll!System.Threading.Tasks.TaskContinuation.InlineIfPossibleOrElseQueue(System.Threading.Tasks.Task task, bool needsProtection)
mscorlib.dll!System.Threading.Tasks.StandardTaskContinuation.Run(System.Threading.Tasks.Task completedTask, bool bCanInlineContinuationTask)
mscorlib.dll!System.Threading.Tasks.Task.FinishContinuations()
mscorlib.dll!System.Threading.Tasks.Task.FinishStageThree()
mscorlib.dll!System.Threading.Tasks.Task<System.__Canon>.TrySetResult(System.__Canon result)
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult(object result)
NG.Data.Spanner.EF.dll!NG.Data.Spanner.EF.Storage.Internal.SpannerRelationalCommand.ExecuteAsync(Microsoft.EntityFrameworkCore.Storage.IRelationalConnection connection, string executeMethod, System.Collections.Generic.IReadOnlyDictionary<string, object> parameterValues, bool closeConnection, System.Threading.CancellationToken cancellationToken) Line 41
[Resuming Async Method]
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.OutputAsyncCausalityEvents.AnonymousMethod__0()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.OutputWaitEtwEvents.AnonymousMethod__0()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
mscorlib.dll!System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action action, bool allowInlining, ref System.Threading.Tasks.Task currentTask)
mscorlib.dll!System.Threading.Tasks.Task.FinishContinuations()
mscorlib.dll!System.Threading.Tasks.Task.FinishStageThree()
mscorlib.dll!System.Threading.Tasks.Task<System.__Canon>.TrySetResult(System.__Canon result)
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult(object result)
NG.Data.Spanner.EF.dll!NG.Data.Spanner.EF.Storage.Internal.SpannerRelationalCommand.ExecuteAsync(NG.Data.Spanner.EF.Storage.Internal.IOBehavior ioBehavior, Microsoft.EntityFrameworkCore.Storage.IRelationalConnection connection, string executeMethod, System.Collections.Generic.IReadOnlyDictionary<string, object> parameterValues, bool closeConnection, System.Threading.CancellationToken cancellationToken) Line 128
[Resuming Async Method]
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.OutputAsyncCausalityEvents.AnonymousMethod__0()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.OutputWaitEtwEvents.AnonymousMethod__0()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
mscorlib.dll!System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action action, bool allowInlining, ref System.Threading.Tasks.Task currentTask)
mscorlib.dll!System.Threading.Tasks.Task.FinishContinuations()
mscorlib.dll!System.Threading.Tasks.Task.FinishStageThree()
mscorlib.dll!System.Threading.Tasks.Task<System.__Canon>.TrySetResult(System.__Canon result)
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Data.Common.DbDataReader>.SetResult(System.Data.Common.DbDataReader result)
NG.Data.Spanner.dll!NG.Data.Spanner.SpannerCommand.ExecuteDbDataReaderAsync(System.Data.CommandBehavior behavior, System.Threading.CancellationToken cancellationToken) Line 67
[Resuming Async Method]
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.OutputAsyncCausalityEvents.AnonymousMethod__0()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.OutputWaitEtwEvents.AnonymousMethod__0()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
mscorlib.dll!System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action action, bool allowInlining, ref System.Threading.Tasks.Task currentTask)
mscorlib.dll!System.Threading.Tasks.Task.FinishContinuations()
mscorlib.dll!System.Threading.Tasks.Task.FinishStageThree()
mscorlib.dll!System.Threading.Tasks.Task<System.__Canon>.TrySetResult(System.__Canon result)
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<Google.Cloud.Spanner.V1.ResultSet>.SetResult(Google.Cloud.Spanner.V1.ResultSet result)
NG.Data.Spanner.dll!NG.Data.Spanner.SpannerConnection.RunQuery(string commandText) Line 118
[Resuming Async Method]
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.OutputAsyncCausalityEvents.AnonymousMethod__0()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.OutputWaitEtwEvents.AnonymousMethod__0()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
mscorlib.dll!System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action action, bool allowInlining, ref System.Threading.Tasks.Task currentTask)
mscorlib.dll!System.Threading.Tasks.Task.FinishContinuations()
mscorlib.dll!System.Threading.Tasks.Task.FinishStageThree()
mscorlib.dll!System.Threading.Tasks.Task<System.__Canon>.TrySetResult(System.__Canon result)
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<Google.Cloud.Spanner.V1.ResultSet>.SetResult(Google.Cloud.Spanner.V1.ResultSet result)
Google.Api.Gax.Grpc.dll!Google.Api.Gax.Grpc.ApiCallRetryExtensions.WithRetry.AnonymousMethod__0(Google.Cloud.Spanner.V1.ExecuteSqlRequest request, Google.Api.Gax.Grpc.CallSettings callSettings)
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.OutputAsyncCausalityEvents.AnonymousMethod__0()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.OutputWaitEtwEvents.AnonymousMethod__0()
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
mscorlib.dll!System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action action, bool allowInlining, ref System.Threading.Tasks.Task currentTask)
mscorlib.dll!System.Threading.Tasks.Task.FinishContinuations()
mscorlib.dll!System.Threading.Tasks.Task.FinishStageThree()
mscorlib.dll!System.Threading.Tasks.Task<System.__Canon>.TrySetResult(System.__Canon result)
mscorlib.dll!System.Threading.Tasks.TaskCompletionSource<System.__Canon>.TrySetResult(System.__Canon result)
mscorlib.dll!System.Threading.Tasks.TaskCompletionSource<System.__Canon>.SetResult(System.__Canon result)
Grpc.Core.dll!Grpc.Core.Internal.AsyncCall<Google.Cloud.Spanner.V1.ExecuteSqlRequest, Google.Cloud.Spanner.V1.ResultSet>.HandleUnaryResponse(bool success, Grpc.Core.Internal.ClientSideStatus receivedStatus, byte[] receivedMessage, Grpc.Core.Metadata responseHeaders)
Grpc.Core.dll!Grpc.Core.Internal.CallSafeHandle.StartUnary.AnonymousMethod__0(bool success, Grpc.Core.Internal.BatchContextSafeHandle context)
Grpc.Core.dll!Grpc.Core.Internal.CompletionRegistry.HandleBatchCompletion(bool success, Grpc.Core.Internal.BatchContextSafeHandle ctx, Grpc.Core.Internal.BatchCompletionDelegate callback)
Grpc.Core.dll!Grpc.Core.Internal.CompletionRegistry.RegisterBatchCompletion.AnonymousMethod__0(bool success)
Grpc.Core.dll!Grpc.Core.Internal.GrpcThreadPool.RunHandlerLoop(Grpc.Core.Internal.CompletionQueueSafeHandle cq, Grpc.Core.Profiling.IProfiler optionalProfiler)
Grpc.Core.dll!Grpc.Core.Internal.GrpcThreadPool.CreateAndStartThread.AnonymousMethod__0()
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state)
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart()

您的问题是您正试图同步实现 Games 而异步实现投影对象。注意以下几点:

.Select(p => new {
    PlayerId = p.PlayerId,
    Games = p.Games.ToList() // sync over async is blocking
}).ToListAsync();

您期望的工作(例如在常规 EF 中)是:

.Select(p => new {
    PlayerId = p.PlayerId,
    Games = p.Games // let the provider handle the enumeration materialization
}).ToListAsync();

但根据您的评论,实际上 return 匿名投影对象上的游戏。那么问题似乎是 EF Core 似乎不会让您摆脱天真的分配(您应该更新问题以表明这一点)。我想知道这是否与 .Include() 在 EF Core 中的工作方式无关。除了告诉您 "cause," 之外,我对 EF 的核心版本还不够熟悉,无法提供很多帮助,但本质上,问题是您正在等待从等待基于该枚举具体化的来源获取枚举器。

所以经过很长时间的调试后我发现了问题并做了一些工作来解决它。我会尽力解释:

我正在构建 EF 核心提供程序Google Spanner 数据库。为此,我正在使用 Google Spanner DotNet API - 虽然它还不是 public 并且非常不成熟 API (实际上它只是自动生成的代码)。

这个 API 使用 gRPC API 我看到的是在第一次异步调用这个 API 时,gRPC 线程(gRPC 有自己的线程池实现) 被使用并将用于下一次执行调用 - 因为延续将 运行 仅在来自 gRPC 线程池的线程上。

EFCore 为使用 System.Interactive.Async 库的 "Games" 列表调用 ToEnumerable。在 ToEnumerable 实现中,它实际上调用了“Result”,它会阻塞执行线程并等待结果。因为使用了 gRPC 线程并等待执行完成,所以我们遇到了死锁...

我的解决方法是使用以下代码:

GrpcEnvironment.SetCompletionQueueCount(1);

这样,允许在 gRPC 线程池的其他线程上 运行 延续。

这只是一种解决方法,应该使用。然而,它同时有助于解决问题...

真正的解决方案应该是 System.Interactive.Async lib 的 EFCore 用法,关于 ToEnumerable...(它应该是纯异步的)。

编辑: 如果它可能与任何人相关: 刚刚为 Google Spanner 数据库发布了一个 EF Core 提供程序: https://github.com/NoGame/NG.Data.Spanner