如何通过实体框架从 C# 中的同步代码并行运行查询
Posted
技术标签:
【中文标题】如何通过实体框架从 C# 中的同步代码并行运行查询【英文标题】:How to run in parallel a query from synchronous code in C# via Entity Framework 【发布时间】:2022-01-09 03:24:33 【问题描述】:我的目标是加快查询速度,我想利用并行性,假设我在 ids 列表中有 2,000 个项目,我将它们分成 4 个列表,每个列表有 500 个 id,我想打开 4 个踏板每个人都将创建一个数据库调用并统一他们的结果,以实现我使用 Parallel.ForEach,但它并没有提高查询的性能,因为它显然不适合 io 绑定操作:Parallel execution for IO bound operations
if 块中的代码对每个使用并行,而 else 块中的代码在常规 foreach 中执行。
问题是包含这个查询的方法不是异步的(因为它是在一个非常遗留的组件中)并且它不能更改为异步,基本上我想在非异步方法中进行并行 io 绑定计算(通过实体框架)。
实现这一目标的最佳做法是什么?我看到也许我可以为此使用Task.WaitAll()
,我不在乎阻塞运行此查询的线程,我更担心从非异步方法调用的Task.WaitAll()
会出现问题
我使用实体框架作为 SQL 数据库上的 ORM,我为每个线程打开一个单独的上下文,因为上下文不是线程安全的。
也许我使用的锁是导致我出现问题的锁,我可以将其更改为ConcurrentDictionary
。
下面代码中描述的场景是我需要改进的场景的简化,在我们的实际应用程序中,我确实需要在加载 id 后读取相关实体,并对它们执行复杂的计算。
代码:
//ids.Bucketize(bucketSize: 500) -> split one big list, to few lists each one with 500 ids
IEnumerable<IEnumerable<long>> idsToLoad = ids.Bucketize(bucketSize: 500);
if (ShouldLoadDataInParallel())
object parallelismLock = new object();
Parallel.ForEach(idsToLoad,
new ParallelOptions MaxDegreeOfParallelism = 4 ,
(IEnumerable<long> bucket) =>
List<long> loadedIds = GetIdsQueryResult(bucket);
lock (parallelismLock)
allLoadedIds.AddRange(loadedIds );
);
else
foreach (IEnumerable<long> bucket in idsToLoad)
List<long> loadedIds = GetIdsQueryResult(bucket);
allLoadedIds.AddRange(loadedIds);
【问题讨论】:
你没有。您改为修复数据访问代码。使用 EF Core 或任何 ORM 按 ID 执行批量删除毫无意义。本案例不涉及任何对象 此外,并行执行批处理操作只会增加阻塞,不会减少阻塞。您仍然使用相同的磁盘、相同的 CPU、相同的事务日志。 你需要执行的SQL是DELETE SomeTable where ID in (...)
。 EF Core 无法做到这一点,但 Dapper 可以。您可以在 DbContext 的连接上使用 Dapper 来执行例如Execute("delete theTable where ID in (@ids):, new ids=someList")
。重复执行以删除批次而不会淹没事务日志
the delete was just to simplify the use case,
在这种情况下,问你真正的问题并描述真正的问题。细节很重要。唯一可以确定的是“并行化”只会损害性能。通常呈指数增长
此外,如果数据来自数据库,您可以修改SELECT
查询以实际删除匹配的行。没有理由将数据拉到客户端只是为了发回 DELETE。
【参考方案1】:
[并行运行多个查询]的最佳做法是什么?
带有单独 DbContext/SqlConnection 的 Parallel.ForEach 是一种很好的方法。
只是并行运行查询在这里并没有真正的帮助。
如果您的 4 个查询针对 4 个单独的数据库,那么您可能会获得不错的改进。但是,在单个实例上并行运行 4 个单独的查询可能不会比运行单个大型查询快,原因有很多。其中包括阻塞、资源争用、服务器端查询并行性以及查询之间的重复工作。
所以
我的目标是加快查询速度,我想利用并行性
因此,这通常不是加快查询速度的好方法。但是,有许多加快查询速度的好方法,所以如果您发布一个新问题,其中包含查询的详细信息以及一些示例数据,您可能会得到一些更好的建议。
【讨论】:
以上是关于如何通过实体框架从 C# 中的同步代码并行运行查询的主要内容,如果未能解决你的问题,请参考以下文章