6

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

想到以下场景......

  1. 创建一个Task(with选项,通过实现让任务捕获上下文并发布UILongRunning来计算哈希并向用户报告进度。IProgess<T>Progess<T> SynchronizationContext

  2. 创建一个Async类似的方法

     async CalculateHashesAsync() 
     {
         // await here for tasks the calculate the hash
         await Task.Rung(() => CalculateHash();
        // how do I report progress???
     }
    
  3. 使用 TPL(或 PLINQ)作为

    void CalcuateHashes()  
    {  
        Parallel.For(0, allFiles.Count, file => calcHash(file)    
        // how do I report progress here?   
    }
    
  4. 使用生产者/消费者队列。
    真不知道怎么办?

书中的作者说...

在池线程上运行一个长时间运行的任务不会造成麻烦。当您并行运行多个长时间运行的任务(尤其是那些阻塞的任务)时,性能可能会受到影响。在这种情况下,通常有比 TaskCreationOptions.LongRunnging 更好的解决方案

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

关于Producer/Consumer作者说...

生产者/消费者队列在并行编程和一般并发场景中都是一种有用的结构,因为它可以让您精确控制一次执行多少工作线程,这不仅对限制 CPU 消耗很有用,而且对其他资源也很有用。

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

我想知道是否有人遇到过这种情况,他们将如何实施?如果不是,那么最有效和/或易于开发/维护的性能是什么(我知道这个词performance是主观的,但让我们考虑一下它工作的非常普遍的情况,并且工作得很好!)

4

1 回答 1

9

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

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

如果您只是从事 CPU 密集型工作,那么最好的解决方案是ParallelPLINQ。如果您只有 I/O 密集型工作,最好的解决方案是使用async. 如果您有一个更现实和复杂的场景(CPU 和 I/O 都工作),那么您应该将 CPU 和 I/O 部分与生产者/消费者队列挂钩,或者使用更完整的解决方案,例如 TPL Dataflow。

TPL Dataflow 与并行 ( MaxDegreeOfParallelism) 和一起工作得很好async,并且在每个块之间都有一个内置的生产者/消费者队列。

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

于 2013-07-05T02:30:52.760 回答