【问题标题】:async/await and Parallel.For loopasync/await 和 Parallel.For 循环
【发布时间】:2016-06-02 15:15:25
【问题描述】:

我正在以两种不同的方式运行 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

问题是为什么会有这样的差异以及使用哪种方式合适。

【问题讨论】:

  • 不要在没有等待结果的情况下调用异步方法。那是火,然后忘记。在异步方法中抛出的任何异常都不会被捕获,它们只会默默地失败。
  • @Pablo 如果您不等待他们,您应该写信到控制台“所有任务已启动”但不是并行完成。当您收到该消息时,parallel.for 正在做的事情仍在进行中。
  • 我认为你不应该在这里使用Parallel.For 基于那个答案或这个stackoverflow.com/questions/19284202/…
  • @Pablo Parallel for 也不会同时启动所有任务。它只是确保它们根据核心数量并行执行。您不妨改用 await Task.WhenAll
  • 所以您使用的是 Parallel.For,然后在您调用 Task.Run 的方法中?这实际上是根据您的需要创建 2 倍的线程。

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


【解决方案1】:

首先,这两个版本都没有任何意义。 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.Forawait:11 毫秒; 2.6 毫秒

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

【讨论】:

    猜你喜欢
    • 2016-02-04
    • 2020-05-30
    • 2016-12-30
    • 2019-07-16
    • 1970-01-01
    • 2020-08-03
    • 2017-04-29
    • 2021-02-27
    • 1970-01-01
    相关资源
    最近更新 更多