【发布时间】:2017-06-03 22:04:27
【问题描述】:
我有一个使用 parallel.foreach 循环的长时间运行的进程。在该循环中,我正在根据传递的内容创建两个不同类的实例,执行次要任务,然后添加到线程安全集合中。完成后,需要将所有数据插入到 sql 中。
我遇到的问题是完成的工作量太大而无法保存在集合中,直到所有处理完成。我必须偶尔将保留的内容推送到 SQL,然后从集合中删除推送的内容,以便可以继续进行更多处理而不会耗尽内存,我不知道最好的方法。如果它不是多线程的,我可以通过检查集合的计数轻松做到这一点,如果它超过一定数量,调用一个函数,该函数将通过批量插入或值表将内容推送到 SQL,然后清除该集合在下一个声明中。在parallel.foreach 中完成此任务的最佳方法是什么?
我愿意使用任何线程安全的集合。到目前为止,我一直在使用ConcurrentQueue 并考虑切换到BlockingCollection,因为我没有看到清除并发队列的方法。我不在乎插入内容的顺序,但我确实需要能够至少删除推送到 sql 的内容。
我最好的解决方案是使用BlockingCollection.GetConsumingEnumerable()。这样,一旦超过 x 数量,我可以将该集合的内容复制到另一个线程安全集合,执行我的插入,然后使用该列表使用 BlockingCollection.GetConsumingEnumerable() 从原始列表中删除。完成后,处理临时列表。我只是认为有一种更好的方法,因为如果我必须一次迭代一个来删除,这有点违背了让它多线程的目的。
我已经看到使用了pulse and wait,但我找不到一个看起来安全的好用例。在我测试集合超过一定数量并在将其插入 sql 之前被清除后,我可能会遇到一些问题。
我正在使用 4.5 框架,我正在管理两个需要推送但不一定同时推送的不同集合。
【问题讨论】:
-
看看TPL Dataflow。它包含协调程序中的生产者/消费者流程所需的所有构建块,在我看来,它非常适合您所描述的问题。绕道而行,看看它提供了什么。你不会后悔的。
标签: c# parallel-processing thread-safety parallel.foreach