【问题标题】:What is the best practice/proper way to invoke an async method within a Parallel.Foreach? [closed]在 Parallel.Foreach 中调用异步方法的最佳实践/正确方法是什么? [关闭]
【发布时间】:2019-07-17 23:19:56
【问题描述】:

我正在创建一个 .net 核心应用程序,我需要在其中调用 async 方法来处理大量对象。我们在Parallel.ForEach 中完成了这项工作,因此我们可以利用并行性更快地完成工作。

服务方法是async 方法,我们无法更改。我的问题是使用 TPL Parallel 时调用此方法的正确方法是什么。

这是一个简化的代码 sn-p(我传递迭代 # 而不是用于演示目的的对象),以及我们的观察结果:

CallSendAsync 方法在内部向 API 发出 HTTP 请求(使用 HttpClient)。

private void ParallelFor()
{
    Parallel.For(0, 100000, i =>
    {
        CallSendAsync(i).GetAwaiter().GetResult();
    });
}

我对上述代码的问题是,它使用了GetAwaiter,这使得async 方法同步。然而,上面的实现非常快。它似乎也更有效地管理系统资源。

另一方面,我有这个:

private void ParallelForWithAsync()
{
    Parallel.For(0, 100000, async i =>
    {
        await CallSendAsync(i);
    });
}

此代码有一个async/await。但是它变得非常慢,性能显着下降。它打开了大量的出站端口,最终导致 HTTP 请求出错。

第三次我也试过这个:

private void TaskWaitAll()
{
    IEnumerable<int> arr = Enumerable.Range(1, 100000);
    Task.WhenAll(arr.Select(CallSendAsync)).GetAwaiter().GetResult();
}

这也有与第二个 sn-p 相似的结果。

【问题讨论】:

    标签: c# async-await task-parallel-library parallel.foreach


    【解决方案1】:

    我需要调用异步方法来处理大量对象的 .net 核心应用程序。我们使用 Parallel.ForEach 完成了这项工作,因此我们可以利用并行性更快地完成工作。

    让我阻止你。您不会“使用并行”来“使事情变得更快”。并行是并发的一种形式(一次做不止一件事),它是一种使用多个线程在多核机器上更快地处理 CPU 绑定算法的并发形式。但是,您的操作根本不受 CPU 限制;它是 I/O 密集型的,这表明 Parallel 是错误的技术。

    如果您希望在基于 I/O 的处理时同时处理多个项目,则适当的解决方案是使用 Task.WhenAll

    然而,它变得非常缓慢,性能显着下降。它打开了大量的出站端口,最终导致 HTTP 请求出错。

    是的。如果您实际发出 十万 个并发 HTTP 请求,这是可以预料的。请记住,IANA ephemeral ports 少于 16k。对于这样的大量请求,您可能希望将其限制在一个更合理的数量 - 例如,一次 20 个。 Parallel.For 将根据 CPU 使用率、线程池中的线程数等正确划分同步工作负载。要限制异步工作,您可以使用 SemaphoreSlim

    private async Task TaskWaitAll()
    {
      var mutex = new SemaphoreSlim(20);
      IEnumerable<int> arr = Enumerable.Range(1, 100000);
      var tasks = arr.Select(async i =>
      {
        await mutex.WaitAsync();
        try { await CallSendAsync(i); }
        finally { mutex.Release(); }
      }).ToList();
      await Task.WhenAll(tasks);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-06
      • 2018-02-14
      • 1970-01-01
      • 2015-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多