插入 SQL 数据库后在 Parallel.ForEach 循环中清除线程安全集合

问题描述 投票:0回答:1

我有一个长时间运行的进程,使用

Parallel.ForEach
循环。在该循环中,我根据传递的内容创建两个不同类的实例,执行次要任务,然后添加到线程安全集合中。完成后,所有数据都需要插入到 SQL 数据库中。

我遇到的问题是完成的工作量太大,无法保留在集合中,直到所有处理完成。我必须偶尔将保留的内容推送到 SQL,然后删除从集合中推送的内容,以便可以继续进行更多处理而不会耗尽内存,但我不知道执行此操作的最佳方法。如果它不是多线程的,我可以通过检查集合的计数轻松做到这一点,如果超过一定数量,则调用一个函数,通过批量插入或值表将内容推送到 SQL,然后清除该集合关于下一个声明。在

Parallel.ForEach
内完成此任务的最佳方法是什么?

我愿意使用任何线程安全的集合。到目前为止,我一直在使用

ConcurrentQueue
并考虑切换到
BlockingCollection
,因为我没有找到清除并发队列的方法。我不关心内容插入的顺序,但我确实需要至少能够删除推送到 SQL 数据库的内容。

我最好的解决方案是使用

BlockingCollection.GetConsumingEnumerable()
。这样,一旦超过 x 数量,我就可以将该集合的内容复制到另一个线程安全集合,执行插入,然后使用该列表使用
BlockingCollection.GetConsumingEnumerable()
从原始列表中删除。完成后,处理临时列表。我只是认为有一种更好的方法,因为如果我必须一次迭代一个来删除,它就违背了多线程的目的。

我已经看到了pulse和wait的使用,但我找不到一个看起来安全的好用例。在我测试集合超过一定数量后,我可以得到一些东西,并在将其插入到 SQ: 数据库之前被清除。

我正在使用 4.5 框架,并且我正在管理两个需要推送但不一定同时推送的不同集合。

c# .net parallel-processing thread-safety parallel.foreach
1个回答
0
投票

我不建议清除并发集合。相反,我会用新线程“替换”它 - 并处理旧线程中的内容,同时其他线程将其内容推送到新线程。

Interlocked.Exchange 是我用来实现此目的的技术。

© www.soinside.com 2019 - 2024. All rights reserved.