async / await和Parallel.For循环

时间:2016-06-02 15:15:26

标签: c# winforms asynchronous task-parallel-library

我以两种不同的方式运行Parallel.For循环:

  1. 不写任何async / await,只是调用Task ReadSensorAsync(int)

    var watch = System.Diagnostics.Stopwatch.StartNew();
    Parallel.For(3, 38,
    index => {
        ReadSensorsAsync(index);
    });
    watch.Stop();
    Console.WriteLine("Parallel finished in {0} ms", watch.ElapsedMilliseconds);
    

    时间显示1ms

  2. 使用async/await

    运行
    var watch = System.Diagnostics.Stopwatch.StartNew();
    Parallel.For(3, 38,
    async index => {
        await ReadSensorsAsync(index);
    });
    watch.Stop();
    Console.WriteLine("Parallel finished in {0} ms", watch.ElapsedMilliseconds);
    

    显示2-5ms

  3. 问题是为什么存在这样的差异以及使用哪种方式。

1 个答案:

答案 0 :(得分:5)

首先,这两个版本都没有任何意义。 Parallel.For用于运行CPU绑定(或可能阻止IO绑定)操作。您正在使用它来启动异步操作。

你不是在等待操作完成,你说这是故意的,但它也很危险:如果在ReadSensorsAsync中发生异常,你就无法捕捉它。

由于启动异步操作应该非常快,要一次启动多个操作,您不需要Parallel.For,您可以使用普通for

for (int i = 3; i < 38; i++)
{
    ReadSensorsAsync(i);
}

(但同样,我不建议忽略返回的Task。)

至于计时,最大的区别可能是因为你忽略了热身:当你第一次调用ReadSensorsAsync时,必须进行JIT编译,对于这种简单的操作,这会显着地扭曲结果

以下是我机器上的数字,格式是“第一次运行”; “第二次跑”:

  • 调用ReadSensorsAsync一次(用于比较):7.6 ms; 0.04毫秒
  • for:7.5毫秒; 0.05毫秒
  • Parallel.For没有await:8.0毫秒; 0.5毫秒
  • Parallel.For await:11毫秒; 2.6毫秒

如您所见,使用Parallel.For只会增加开销。将它与await一起使用会增加更多开销,因为启动async方法需要创建状态机,这需要一些时间。