我们正在构建一个使用ef core 3.0和Pomelo.EntityFrameworkCore.MySql提供程序3.0的asp.net core 3应用程序。
现在,我们正在尝试将所有数据库调用从同步替换为异步,例如:
//from
dbContext.SaveChanges();
//to
await dbContext.SaveChangesAsync();
不幸的是,我们遇到两个问题:
与mysql异步使用ef core的推荐方法是什么?任何能有效地与MySql异步使用ef-core 3的可行示例或证据。
答案 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 倍。