说我有以下型号:
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();
当我通过Console 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
有一个调用“结果”,它实际上阻止了执行线程.
有没有人遇到过这种行为,也许有一些解决方法?
请注意,如果我没有加载“游戏”实体,那么一切也正常……
编辑:添加StackTrace :(查看对ToEnumerable的调用)
未标记21672 5工作线程grpc 0(cq 0)system.interactive.Async.dll!System.Linq.AsyncEnumerable.ToEnumerable_ 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_(System.Collections.Generic.IAsyncEnumerable source)
mscorlib.dll!System.Collections.Generic.List.List(System.Collections.Generic.IEnumerable collection)
System.Core.dll!System.Linq.Enumerable.ToList(System.Collections.Generic.IEnumerable source)
[轻量级功能]
Microsoft.EntityFrameworkCore.dll!Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.SelectAsyncEnumerable.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,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.SpannerAsyncEnumerator.MoveNext(System.Threading.CancellationToken cancellationToken)第55行
[恢复异步方法]
mscorlib.dll!System.Runtime.CompilerServices.AsyncmethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext,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.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,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,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,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(System .__ Canon result)
mscorlib.dll!System.Threading.Tasks.taskcompletionsource.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,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任务,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.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连接,字符串executeMethod,System.Collections.Generic.IReadOnlyDictionary parameterValues,bool closeConnection,System.Threading.CancellationToken cancellationToken)第41行
[恢复异步方法]
mscorlib.dll!System.Runtime.CompilerServices.AsyncmethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext,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(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连接,string executeMethod,System.Threading.CancellationToken cancellationToken)第128行
[恢复异步方法]
mscorlib.dll!System.Runtime.CompilerServices.AsyncmethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext,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(System .__ Canon result)
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult(System.Data.Common.DbDataReader result)
NG.Data.Spanner.dll!NG.Data.Spanner.SpannerCommand.ExecuteDbDataReaderAsync(System.Data.CommandBehavior behavior,System.Threading.CancellationToken cancellationToken)第67行
[恢复异步方法]
mscorlib.dll!System.Runtime.CompilerServices.AsyncmethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext,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(System .__ Canon result)
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult(Google.Cloud.Spanner.V1.ResultSet result)
NG.Data.Spanner.dll!NG.Data.Spanner.SpannerConnection.RunQuery(string commandText)第118行
[恢复异步方法]
mscorlib.dll!System.Runtime.CompilerServices.AsyncmethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext,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(System .__ Canon result)
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder.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,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(System .__ Canon result)
mscorlib.dll!System.Threading.Tasks.taskcompletionsource.TrySetResult(System .__ Canon result)
mscorlib.dll!System.Threading.Tasks.taskcompletionsource.SetResult(System .__ Canon result)
Grpc.Core.dll!Grpc.Core.Internal.AsyncCall.HandleUnaryResponse(bool成功,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成功,Grpc.Core.Internal.BatchContextSafeHandle ctx,Grpc.Core.Internal.BatchCompletionDelegate回调)
Grpc.Core.dll!Grpc.Core.Internal.CompletionRegistry.RegisterBatchCompletion.AnonymousMethod__0(bool成功)
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(对象状态)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext,System.Threading.ContextCallback回调,对象状态)
mscorlib.dll中!System.Threading.ThreadHelper.ThreadStart()
解决方法
我正在为Google Spanner db构建EF Core提供程序.为此,我使用的是Google Spanner DotNet API – 尽管它尚未公开且非常不成熟的API(实际上它只是自动生成的代码).
这个API使用gRPC API,我看到的是在第一次使用此API的异步调用时,gRPC线程(gRPC有自己的线程池实现)被使用并将用于下一次执行调用 – 因为continuation将继续仅从gRPC线程池中的此线程运行.
EFCore为使用system.interactive.Async lib的“Games”列表调用ToEnumerable.在ToEnumerable实现上,它实际上调用“Result”来阻止执行线程并等待结果.因为使用了gRPC线程并等待执行完成所以我们有一个死锁…
GrpcEnvironment.SetCompletionQueueCount(1);
这样,允许continuation在gRPC线程池的其他线程上运行.
这只是一种解决方法,应该使用.然而,在此期间它有助于解决问题……
真正的解决方案应该是在system.interactive.Async lib的EFCore用法中,关于ToEnumerable …(它应该是纯异步).
编辑:
如果它可能与任何人相关:
刚刚发布了针对Google Spanner db的EF Core提供商:
https://github.com/NoGame/NG.Data.Spanner
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。