使用async-await运行I / O的任务,用于并行生产者 - 消费者

时间:2016-03-25 23:25:47

标签: c# .net asynchronous parallel-processing async-await

假设我有一个像this这样的生产者 - 消费者模式。该帖子还解释了为什么在这种特定情况下使用TPL Dataflow可能不是最佳的。这就是为什么这个问题改为使用任务。

+----------+                          +----------------+                           +-----------+ 
|   Task   |                          |      Task      |                           |   Task    |
|Read files|-----BlockingCollection-->|Process values  |----BlockingCollection---->|Write files|
+----------+   |                      |of data logger 1|  |                        +-----------+ 
               |                      +----------------+  |             
               |                      +----------------+  |
               |                      |      Task      |  |
               |-BlockingCollection-->|Process values  |--|
               |                      |of data logger 2|  |
               |                      +----------------+  |
                ...                       (n Tasks)        ...

在此实现中,读取和写入需要与处理同时发生,因此每个都使用Task来实现此目的。如果我使用阻塞函数进行读写,那么这将是一种方法,但异步读/写怎么样?现在我想知道在这种特定情况下我是否理解正确使用async-await。由于我需要并行性,因此读取和写入仍应在单独的Task中进行。我不想在等待I / O结果时浪费CPU周期,因此async-await似乎是解决方案。

以此伪实现为例。 ReadAllLinesAsync将是一个类似this

的实现
BlockingCollection<string []> queue = new BlockingCollection<string []>(100);
var pathsToFiles = files;
await Task.Run(async () => 
{
    //This is a dummy for the "Read files"-object's function call
    for(int i=0; i<pathsToFiles.Length; i++)
    {
        string[] file = await ReadAllLinesAsync(pathsToFiles[i]);
        queue.Add(file);
    }
    queue.CompleteAdding();
} 

第一个问题是,示例代码是否正确使用async-await? 第二个问题是,与阻塞I / O相比,这是否提高了效率,是否阻止了CPU等待I / O?

我阅读了几篇文章并发布了async-await主题,并且不得不说这是非常复杂的所有做法和不做。具体来说,我读过Steven Cleary的articles

1 个答案:

答案 0 :(得分:0)

使用await来执行IO时保存线程是正确的。它是否会让你获得任何东西取决于线程是否是你的稀缺资源。

如果线程池过载,这可能会有很大帮助。另一方面,如果线程池过载,您可能无论如何都要超额订阅磁盘。您可以通过使用await SemaphoreSlim.WaitAsync()等内容限制未完成IO的数量来提高磁盘使用率。

IO效率不受呼叫方式(同步或异步)的影响。通常,异步IO使用更多的CPU,这在这里可以忽略不计,因为IO成本占主导地位。

这是一个GUI场景吗?否则我不明白使用await Task.Run