如何在异步模式下正确使用ef core 3的Pomelo.EntityFrameworkCore.MySql提供程序?

时间:2019-11-26 11:02:25

标签: async-await .net-core-3.0 ef-core-3.0 pomelo-entityframeworkcore-mysql

我们正在构建一个使用ef core 3.0和Pomelo.EntityFrameworkCore.MySql提供程序3.0的asp.net core 3应用程序。

现在,我们正在尝试将所有数据库调用从同步替换为异步,例如:

//from
dbContext.SaveChanges();
//to
await dbContext.SaveChangesAsync();

不幸的是,我们遇到两个问题:

  1. 与相同的同步调用测试相比,与服务器的连接数显着增加
  2. 我们的应用程序的平均处理速度显着下降

与mysql异步使用ef core的推荐方法是什么?任何能有效地与MySql异步使用ef-core 3的可行示例或证据。

2 个答案:

答案 0 :(得分:1)

如果不查看更多代码,很难说这里的问题是什么。您可以为我们提供一个可以重现此问题的小型示例应用程序吗?

任何DbContext实例都使用一个数据库连接进行正常操作,而与调用同步方法还是异步方法无关。

  

与相同的同步调用测试相比,与服务器的连接数显着增加

我们在谈论什么样的测试?他们是自动化的吗?如果是这样,正在运行多少测试?由于异步调用的性质,如果并行运行1000个测试,那么每个测试都有自己的DbContext,最终将获得1000个并行连接。

尽管使用Pomelo,您最终不会再拥有1000个线程,就像使用Oracle的提供程序一样。

更新

  

我们测试了asp.net核心调用(mvc),该调用转到db并读写东西。 50个线程,使用限制为500的DbContextPool。如果我使用dbContext.SaveChanges(),Add(),则所有上下文方法都同步,我使用dbContext.SaveChangesAsnyc()以及AddAsnyc,ReadAsync等与MySql建立了约50个连接,我最终看到与MySql的最大连接数为250,并且该页面的平均响应时间下降了2到3倍。

(我在下面谈论ASP.NET和请求。并行运行测试用例也是如此。)

如果您一直使用异步方法,则不会阻塞任何内容,因此您的50个线程可以自由处理接下来的50个请求,而数据库仍在对前50个请求执行查询。

这将一次又一次地发生,因为ASP.NET处理请求的速度可能比数据库返回其结果的速度快。因此,您最终将获得大量并行数据库查询。

在执行Sync方法时不会发生这种情况,因为每个线程都会阻塞,并且您最终最多只能进行50个并行查询(每个线程一个)。

所以这是预期的行为,只是异步方法调用的结果。

您始终可以修改代码或Web服务器配置,以限制并发ASP.NET请求的数量。

  

50个线程,使用限制为500的DbContextPool。

还请注意,DbContextPool并没有限制可以同时存在多少个DbContext对象,而仅限制了池中将保留多少个对象。因此,如果将DbContextPool设置为500,则可以创建500多个上下文,但是使用它们后,只有500个可以保持活动状态。

更新

lock-free database pool programming中有一个关于@roji的非常有趣的低级讨论,它解决了此问题并占据了您的位置,即连接池中应该有一个上限,超过该上限会导致阻塞并为这种行为提供了很好的理由。

根据MySqlConnector的@bgrainger,这就是已经实现的方式(文档没有明确声明,但是现在已经做了)。 MaxPoolSize连接字符串选项的默认值为100,因此,如果使用连接池,并且不覆盖此值,并且不使用多个连接池,则不应使用在给定的时间超过100个活动连接。

来自GitHub

  

这是一个文档错误,如果您将文档解释为意味着可以创建无限数量的连接。

     

当池为true时,每个连接池(每个唯一的连接字符串都有一个)仅允许同时打开MaximumPoolSize个连接。对MySqlConnection.Open的每个其他调用都将阻塞,直到连接返回到池中为止。

     

当池为false时,可以同时打开的连接数没有限制。由用户来管理并发。

答案 1 :(得分:1)

检查您的连接字符串中是否有 Pooling=false,如 Bradley Grainger 中的 comments 所述。

从连接字符串中删除 pooling=false 后,我的应用程序的运行速度确实提高了 3 倍。