PLINQ vs Tasks vs Async vs Producer / Consumer队列?用什么?

时间:2013-07-04 14:17:30

标签: c# multithreading visual-studio-2012 task-parallel-library async-await

我正在阅读C# 5.0 in nutshell,在阅读了作者的观点之后,我对我应该采用什么感到困惑。我的要求就是说我有一个很长时间运行(计算量很大)的任务,例如,计算数百万个文件的SHA1(或其他一些)哈希,或者其他任何东西都是计算量很大并且可能需要一些时间,我应该采用什么方法来开发它(如果重要的是winforms,使用VS 2012,C#5.0),so that I can also report progress to the user

以下情景会浮现在脑海中......

  1. 通过实施Task或{{1 让任务捕获LongRunning上下文并发布到用户界面。

  2. 创建一个{/ 1}}方法,如

    IProgess<T>
  3. 使用TPL(或PLINQ)作为

    Progess<T>
  4. 使用生产者/消费者队列 真的不知道怎么办?

  5. 书中的作者说......

      

    在池化线程上运行一个长时间运行的任务不会导致   麻烦。当你并行运行多个长时间运行的任务时   (特别是那些阻止)表现会受到影响的人。在那里面   情况下,通常有更好的解决方案   TaskCreationOptions.LongRunnging

         
        
    • 如果任务是IO绑定的,可以使用TaskCompletionSource和异步函数   使用回调而不是线程来实现并发。
    •   
    • 如果任务是计算绑定的,那么生产者/消费者队列可以限制这些任务的并发性,避免饥饿   其他线程和流程。
    •   

    关于SynchronizationContext作者说......

      

    生产者/消费者队列是一个有用的结构,两者并行   编程和一般并发场景,因为它给你精确   控制一次执行多少个工作线程,这很有用   不仅限制CPU消耗,还限制其他资源。

    那么,我应该不使用任务,这意味着第一个选项是什么?第二个是最好的选择吗?还有其他选择吗?如果我遵循作者的建议,并实施生产者/消费者,我将如何做到这一点(我甚至不知道如何在我的方案中开始使用生产者/消费者,如果那是最好的方法!)

    我想知道是否有人遇到过这种情况,他们将如何实施?如果没有,那么最有效和/或易于开发/维护的是什么(我知道Async这个词是主观的,但我们只考虑它的工作原理,并且效果很好!)

1 个答案:

答案 0 :(得分:8)

  

真正长时间运行(计算量很大)的​​任务,例如,计算数百万个文件的SHA1(或其他一些)哈希

该示例显然具有繁重的CPU(散列)和I / O(文件)组件。也许这是一个非代表性的例子,但根据我的经验,即使安全散列也比从磁盘读取数据快得多。

如果你只有CPU限制工作,最好的解决方案是Parallel或PLINQ。如果您只有I / O绑定工作,最好的解决方案是使用async。如果你有一个更现实和复杂的场景(CPU和I / O都工作),那么你应该连接你的CPU和I / O部件与生产者/消费者队列使用更完整的解决方案,如TPL Dataflow。

TPL Dataflow适用于并行(MaxDegreeOfParallelism)和async,并且在每个块之间都有一个内置的生产者/消费者队列。

混合大量I / O和CPU使用时要记住的一件事是,不同的情况会导致大量不同的性能特征。为了安全起见,您需要限制通过队列的数据,这样您就不会遇到内存使用问题。 TPL Dataflow通过BoundedCapacity内置了对限制的支持。