繁体   English   中英

IO绑定操作的并行执行

[英]Parallel execution for IO bound operations

我已阅读TPL和任务库文档封面。 但是,我仍然无法清楚地理解以下案例,现在我需要实施它。

我会简化我的情况。 我有一个长度为1000的IEnumerable<Uri> 。我必须使用HttpClient向它们发出请求。

我有两个问题。

  1. 没有太多计算 ,只是在等待Http请求。 在这种情况下,我还可以使用Parallel.Foreach()吗?
  2. 如果使用Task ,创建大量的最佳实践是什么? 假设我使用Task.Factory.StartNew()并将这些任务添加到列表中并等待所有这些任务。 是否有一个功能(如TPL分区程序)控制最大任务的数量和我可以创建的最大HttpClient

在SO上有几个类似的问题,但没有人提到最大值 该要求仅使用具有最大HttpClient的最大任务。

先感谢您。

i3arnon对TPL Dataflow的回答很好; 如果您混合使用CPU和I / O绑定代码,则数据流非常有用。 我将回应他的观点,即Parallel是为CPU绑定代码而设计的; 它不是基于I / O的代码的最佳解决方案, 尤其不适合异步代码。

如果您想要一个适用于大多数I / O代码的替代解决方案 - 并且不需要外部库 - 您正在寻找的方法是Task.WhenAll

var tasks = uris.Select(uri => SendRequestAsync(uri)).ToArray();
await Task.WhenAll(tasks);

这是最简单的解决方案,但它确实具有同时启动所有请求的缺点。 特别是如果所有请求都转到相同的服务(或一小组服务),这可能会导致超时。 要解决这个问题,你需要使用某种限制......

是否有一个功能(如TPL分区程序)控制最大任务的数量和我可以创建的最大HttpClient?

TPL Dataflow有一个很好的MaxDegreeOfParallelism ,它一次只能启动这么多。 您还可以使用另一个内置函数SemaphoreSlim来限制常规异步代码:

private readonly SemaphoreSlim _sem = new SemaphoreSlim(50);
private async Task SendRequestAsync(Uri uri)
{
  await _sem.WaitAsync();
  try
  {
    ...
  }
  finally
  {
    _sem.Release();
  }
}

如果使用Task,创建大量的最佳实践是什么? 假设我使用Task.Factory.StartNew()并将这些任务添加到列表中并等待所有这些任务。

你实际上不想使用StartNew 它只有一个适当的用例(基于动态任务的并行性),这是非常罕见的。 如果您需要将工作推送到后台线程,现代代码应该使用Task.Run 但是你甚至不需要开头,所以StartNewTask.Run都不适合这里。

在SO上有几个类似的问题,但没有人提到最大值。 该要求仅使用具有最大HttpClient的最大任务。

最大值是异步代码真正变得棘手的地方。 使用CPU绑定(并行)代码,解决方案显而易见:您使用尽可能多的线程。 (好吧,至少你可以那里开始并根据需要进行调整)。 使用异步代码,没有明显的解决方案。 这取决于很多因素 - 你有多少内存,远程服务器如何响应(速率限制,超时等)等。

这里没有简单的解决方案。 您只需要测试您的特定应用程序如何处理高级别的并发性,然后限制到较低的数字。


我有一些幻灯片可以解释何时适合不同的技术(并行,异步,TPL数据流和Rx)。 如果您更喜欢书面描述和食谱,我想您可能会从我的并发书中受益。

在这种情况下我还可以使用Parallel.Foreach吗?

这不太合适。 Parallel.Foreach更适用于CPU密集型工作。 它也不支持异步操作。

如果使用Task ,创建大量的最佳实践是什么?

请改用TPL Dataflow块。 您不会创建大量等待线程可用的任务。 您可以配置最大任务量,并将其重用于同时位于缓冲区中等待任务的所有项目。 例如:

var block = new ActionBlock<Uri>(
    uri => SendRequestAsync(uri),
    new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 50 });

foreach (var uri in uris)
{
    block.Post(uri);
}

block.Complete();
await block.Completion;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM