如何尽快有效地制作1000个Web请求

时间:2015-12-24 18:36:55

标签: c# asynchronous concurrency

我需要从C#控制台应用程序制作100,000个轻量级(即小内容长度)Web请求。我能做到这一点的最快方法是什么(即在最短的时间内完成了所有请求)以及我应该遵循哪些最佳做法?我无法解雇,因为我需要捕捉回复。

据推测,我想要使用async网络请求方法,但我想知道存储所有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

还需要其他什么吗?

3 个答案:

答案 0 :(得分:2)

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

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

您需要凭经验确定正确的DOP。只需尝试不同的价值观没有理论上的方法来获得最佳价值,因为它取决于许多事情。

连接限制是唯一的限制。

  

response.GetAwaiter()。OnCompleted

不确定你在那里想要做什么......如果你发表评论,我会解释这个误解。

答案 1 :(得分:1)

您要执行的操作是

  1. 调用I / O方法
  2. 处理结果
  3. 您应该使用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);
    

    要等待任务完成,您可以使用await Task.WhenAll(tasks)方法中的asyncTask.WaitAll(tasks)中的Main()

    在Web服务上投掷100k请求可能会将其删除,因此您必须对其进行限制。您可以查看this question的答案,找到一些选项。

答案 2 :(得分:0)

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

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