如何快速有效地发出1000个web请求

本文关键字:1000个 web 请求 何快速 有效地 | 更新日期: 2023-09-27 18:28:03

我需要从C#控制台应用程序发出100000个轻量级(即小内容长度)web请求。我能做到这一点的最快方法是什么(即在尽可能短的时间内完成所有请求)?我应该遵循哪些最佳实践?我不能开火忘记,因为我需要捕捉回应。

据推测,我想使用async web请求方法,但我想知道存储所有Task延续和编组的开销会产生什么影响

内存消耗不是一个整体问题,目标是速度。

大概我也想利用所有可用的核心。

所以我可以做这样的事情:

Parallel.ForEach(iterations, i =>
{
    var response = await MakeRequest(i);
    // do thing with response
});

但这不会让我比我的核心数量更快。

我可以做:

Parallel.ForEach(iterations, i =>
{
    var response = MakeRequest(i);
    response.GetAwaiter().OnCompleted(() =>
    {
        // do thing with response
    });
});

但是在ForEach之后,我该如何保持程序运行呢。抓住所有的TasksWhenAll感觉很臃肿,有没有现有的模式或助手可以拥有某种任务队列?

有什么方法可以做得更好吗?我应该如何处理节流/错误检测?例如,如果远程端点响应缓慢,我不想继续发送垃圾邮件

我知道我还需要做:

ServicePointManager.DefaultConnectionLimit = int.MaxValue

还有什么需要的吗?

如何快速有效地发出1000个web请求

Parallel类不适用于异步循环体,因此您无法使用它。循环体几乎立即完成并返回任务。这里没有并行性的好处。

这是一个很容易的问题。使用其中一个标准解决方案与给定DOP异步处理一系列项目(此解决方案很好:http://blogs.msdn.com/b/pfxteam/archive/2012/03/05/10278165.aspx.使用最后一段代码)。

您需要根据经验确定正确的DOP。只需尝试不同的价值观。没有从理论上得出最佳价值的方法,因为它取决于许多因素。

连接限制是唯一的限制。

response.GetAwaiter().OnCompleted

不确定你想在那里完成什么。。。如果你有意见,我会解释这个误解。

要执行的操作是

  1. 调用I/O方法
  2. 处理结果

您应该使用async版本的I/O方法,这是正确的。更重要的是,您只需要1个线程就可以启动所有的I/O操作。这里的并行性不会让您受益。

您将从第二部分的并行性中受益——处理结果,因为这将是一个CPU绑定的操作。幸运的是,async/await将为您完成所有工作。控制台应用程序没有同步上下文。这意味着await之后的方法部分将在线程池线程上运行,以最佳方式利用所有CPU核心。

private async Task MakeRequestAndProcessResult(int i)
{
    var result = await MakeRequestAsync();
    ProcessResult(result);
}
var tasks = iterations.Select(i => MakeRequestAndProcessResult(i)).ToArray();

要在具有同步上下文(例如WPF或WinForms)的环境中实现相同的行为,请使用ConfigureAwait(false)

var result = await MakeRequestAsync().ConfigureAwait(false);

要等待任务完成,可以在async方法中使用await Task.WhenAll(tasks),或者在Main()中使用Task.WaitAll(tasks)

向web服务抛出10万个请求可能会杀死它,所以你必须限制它。你可以查看这个问题的答案,找到一些如何做到这一点的选项。

如果显式设置ParallelOptions参数的MaxDegreeOfParallelism属性(在ForEach的重载中有该参数),则Parallel.ForEach应该能够使用比核心更多的线程-请参阅https://msdn.microsoft.com/en-us/library/system.threading.tasks.paralleloptions.maxdegreeofparallelism(v=vs.110).aspx

您应该能够将其设置为1000,以使其使用1000个线程甚至更多,但由于线程开销,这可能效率不高。你可能希望进行实验(例如,在100秒内从100步循环到1000步,尝试每次提交1000个请求,从开始到结束),甚至设置某种自调整算法。