问题我的任务是解决(根据我的理解)典型的生产者/消费者问题。我们有24/7/365的数据传入。传入数据(称为原始数据)存储在表中,并且对最终用户不可用。然后,我们选择尚未处理的所有原始数据并逐个开始处理。处理完每个数据单元后,它将存储在另一个表中,现在可供客户端应用程序使用。 从加载原始数据到持久处理数据的过程平均需要2-5秒。但它高度依赖于我们用来处理数据的第三方Web服务。如果Web服务很慢,我们就不再像处理数据那样快速处理数据并累积积压,从而导致客户放弃实时订阅源。 我们希望将此过程变为多线程。根据我的研究,我可以看到这个过程可以分为三个不同的部分:
LOADING - 无限期运行的加载程序任务(生产者),将未处理的数据从DB加载到BlockingCollection<T>
(或并发集合的其他变体)。我选择的BlockingCollection
是因为它在设计时考虑了生产者/消费者模式,并提供GetConsumingEnumerable()
方法。
处理 - 使用上述BlockingCollection<T>
数据的多个消费者。在其当前实现中,我有Parallel.ForEach
循环通过GetConsumingEnumerable()
,在每次迭代时启动一个具有两个任务延续的任务:任务的第一步是调用第三方Web服务,等待结果和输出要使用的第二个任务的结果。第二个任务根据第一个任务的输出进行计算,并输出第三个任务的结果,基本上只将结果存储到第二个BlockingCollection<T>
(这个是输出集合)。所以我的消费者也是有效的生产者。理想情况下,任务1加载的每个数据单元都将排队等待并行处理。
PERSISTING - 单个消费者针对上述第二个BlockingCollection
运行,并将处理后的数据保存到数据库中。
我面临的问题是上面列表中的项目编号2。它似乎不够快(仅使用Parallel.ForEach
)。我尝试在Parallel.ForEach
内部而不是直接启动一个继续任务,启动一个包装线程,然后启动处理任务。但这导致OutOfMemory异常,因为线程计数失控并很快达到1200。我也尝试使用ThreadPool安排工作但没有用。
请问您的方法是否足以满足我们的需求,或者有更好的方法吗?
答案 0 :(得分:3)
如果瓶颈是某些第三方服务,并且这不会处理并行执行,但会将您的请求排队,那么您就无法做任何事情。
但首先你可以试试这个:
这就是我现在所能想到的所有内容。
答案 1 :(得分:2)
我最近遇到的问题与你的问题非常相似, 这就是我所做的,希望它可能会有所帮助:
这解决了我的问题,我希望它对你有帮助,如果有任何疑问问我,我会在这里解释一下......