阻止EF性能的SNIReadSyncOverAsync和WaitForSingleObject?

我正在对使用EF(System.Data.Entities)从sql DB读取的WCF服务进行一些分析。 当我启动多个并行服务器的客户端时,CPU都会达到100%,性能通常是坦克,一切都陷入困境。

在使用并发分析器进行分析时,我发现85%的时间花在同步上,只有大约4%是实际的代码执行。 深入研究堆栈跟踪,大多数同步似乎来自System.Data.SqlClient.TdsParserStateObject.ReadSniSyncOverAsync中对WaitForSingleObject的调用。 堆栈显示调用转到本机方法包装器,然后在kernel32.dll!_WaitForSingleObject结束。

有谁之前经历过这个吗? 对此有什么办法吗? 我并没有真正抛出荒谬的负载,只有大约20个并行客户端,并且它都是只读的,所以我很惊讶线程甚至会费心去同步。

我已经和它斗争了一个星期了,我无法解释它。 任何帮助,将不胜感激!

您是否能够将其提炼为可以重现问题的小代码示例? 您使用的是哪个版本的EF?

以下是根据您目前提供的信息进行的一些观察。

EF异步

任何小于EF 6的东西总是同步的。 使用EF 6,您可以选择使用异步方法 。 但是,除非您的WCF服务也使用异步模式,否则不要这样做。

WCF异步

您可以编写实现异步的WCF服务。 有关更多信息,请参阅此文档 。

如果您使用上述方法之一,但不是两者,您的代码将不是异步的,但会产生不必要的同步开销。 特别是避免使用Task.Run()或等价物,因为这些只会将工作移动到另一个线程而不会实际提高吞吐量。

初始化

最后,另一个无关的想法。 您的问题可能与EF初始化有关吗? 当EF为模型构建元数据时,每个连接字符串执行一次。 如果多个线程尝试使用相同的模型并且该模型尚未初始化,则所有线程都将阻塞,直到初始化完成。 要查看这是否是您的问题,请拨打该服务并允许其完成。 然后提交您的20个并行请求。 他们还能最大化CPU吗?