无限期地运行生产者/消费者应用程序

时间:2012-08-30 11:28:05

标签: c# multithreading parallel-processing producer-consumer

问题我的任务是解决(根据我的理解)典型的生产者/消费者问题。我们有24/7/365的数据传入。传入数据(称为原始数据)存储在表中,并且对最终用户不可用。然后,我们选择尚未处理的所有原始数据并逐个开始处理。处理完每个数据单元后,它将存储在另一个表中,现在可供客户端应用程序使用。 从加载原始数据到持久处理数据的过程平均需要2-5秒。但它高度依赖于我们用来处理数据的第三方Web服务。如果Web服务很慢,我们就不再像处理数据那样快速处理数据并累积积压,从而导致客户放弃实时订阅源。  我们希望将此过程变为多线程。根据我的研究,我可以看到这个过程可以分为三个不同的部分:

  1. LOADING - 无限期运行的加载程序任务(生产者),将未处理的数据从DB加载到BlockingCollection<T>(或并发集合的其他变体)。我选择的BlockingCollection是因为它在设计时考虑了生产者/消费者模式,并提供GetConsumingEnumerable()方法。

  2. 处理 - 使用上述BlockingCollection<T>数据的多个消费者。在其当前实现中,我有Parallel.ForEach循环通过GetConsumingEnumerable(),在每次迭代时启动一个具有两个任务延续的任务:任务的第一步是调用第三方Web服务,等待结果和输出要使用的第二个任务的结果。第二个任务根据第一个任务的输出进行计算,并输出第三个任务的结果,基本上只将结果存储到第二个BlockingCollection<T>(这个是输出集合)。所以我的消费者也是有效的生产者。理想情况下,任务1加载的每个数据单元都将排队等待并行处理。

  3. PERSISTING - 单个消费者针对上述第二个BlockingCollection运行,并将处理后的数据保存到数据库中。

  4. 我面临的问题是上面列表中的项目编号2。它似乎不够快(仅使用Parallel.ForEach)。我尝试在Parallel.ForEach内部而不是直接启动一个继续任务,启动一个包装线程,然后启动处理任务。但这导致OutOfMemory异常,因为线程计数失控并很快达到1200。我也尝试使用ThreadPool安排工作但没有用。

    请问您的方法是否足以满足我们的需求,或者有更好的方法吗?

2 个答案:

答案 0 :(得分:3)

如果瓶颈是某些第三方服务,并且这不会处理并行执行,但会将您的请求排队,那么您就无法做任何事情。

但首先你可以试试这个:

  • 使用ThreadPool或Tasks(那些也会使用ThreadPool) - 不要自己启动线程
  • 尝试将您的请求设为异步,而不是仅使用线程
  • 通过性能分析器运行您的服务/应用程序,并检查“浪费”您的时间
  • 对第三方服务进行加标/检查并查看它如何处理并行请求
  • 考虑缓存此服务的答案(如果可能)

这就是我现在所能想到的所有内容。

答案 1 :(得分:2)

我最近遇到的问题与你的问题非常相似, 这就是我所做的,希望它可能会有所帮助:

  1. 看起来你的第一和第三部分相当简单,而且可以 在各自的线程上管理没有任何问题,
  2. 首先必须在新线程上启动第二部分,然后使用System.Threading.timer进行Web服务调用, 调用Web服务的方法通过异步调用它将响应(结果)传递给处理方法,让它按照自己的步调处理数据,
  3. 这解决了我的问题,我希望它对你有帮助,如果有任何疑问问我,我会在这里解释一下......