【发布时间】:2020-10-23 14:49:34
【问题描述】:
我正在编写一个代码来遍历一个庞大的对象列表,以便将它们保存在 DB 中。
我有一个计数器,每次迭代都会增加,当它达到 500 时,我将所有内容都保存在 DB 中(来自 StringBuilder)。
如果我按顺序进行,我没有问题,但需要很长时间。这就是为什么我想使用并行性来做到这一点。
我已经看到我无法为所有线程创建一个 StringBuilder,因此我需要为每个线程创建一个。
我的问题是: 如何为每个线程创建一个 StringBuilder? 然后,当静态计数器达到 500 个循环时,如何将所有 StringBuilder 对象持久化到 DB 并清空它们?
我有以下代码:
int counter = 0;
Parallel.ForEach(myList, element =>
{
lock (balanceLock)
{
counter++;
}
var sb = new StringBuilder(); //I need one StringBuilder for thread, not for iteration
...
if (decimal.Remainder(counter, 500) == 0)
lock (balanceLock)
{
persistInDB(sb.toString());
sb.Clear();
}
});
【问题讨论】:
-
如果你在里面使用锁,那么使用
Parallel.ForEach是没有意义的。该方法适用于数据并行 - 处理大量本地内存数据。不是通用并行执行,也绝对不是用于执行远程数据库调用 -
你想做什么?您描述了您认为解决方案的样子,而不是实际问题。
huge list将是例如 1M 内存对象。 100K会很多。 500 是极少量的数据。您可以使用单个 INSERT 命令插入所有这些行,或者使用 SqlBulkCopy 以使用最少的日志记录在单个批量操作中插入数据 -
我想指出的是,在使用任务时,系统决定何时将工作交给另一个线程。
-
如果您有一个大集合要发送到数据库,您可以使用FastMember's ObjectReader together with SqlBulkCopy 将数据插入数据库。
-
关键是我在内存中的列表中最多可以有 10M 项,并且每个项都会在数据库上生成不同的查询。这就是并行处理的原因
标签: c# parallel.foreach