C# - 执行200个http获取请求并输出结果

时间:2016-04-29 14:57:10

标签: c# http asynchronous parallel-processing console-application

我有一个控制台应用程序,用户输入一个菜单选项(1-5),我执行一些功能并输出结果。

其中一项功能是对某些网址执行200次http获取请求,获取所有结果,对其进行一些处理并输出给用户。

这是我目前的代码:

        Parallel.For(0, 200, i =>
        {
            String[] words = webApi.getSplittedClassName();
            for (int j = 0; j < words.Length; j++)
            {
                wordsList.Add(words[j]);
            }

        });

getSplittedClassName

    public string[] getSplittedClassName()
    {
        HttpResponseMessage response = null;
        try
        {
            response = httpClient.GetAsync(url).Result;
        }
        catch (WebException e)
        {
            return null;
        }
        return parser.breakdownClassName(response);
    }

现在,由于用户输入了一个选项号,程序执行了所需的功能,然后我输出了输出,我认为没有必要在async中进行http工作,所以它全部是同步的。

问题是它需要花费很多时间来处理请求,大约30-40秒......这有意义吗?

基本上有3个功能:执行1个请求,执行3个请求和200个请求。

执行200个请求并等待所有结果的最佳选择是什么?它应该是同步的,就像我只发出一个请求一样吗?

感谢

1 个答案:

答案 0 :(得分:2)

Parallel.For()倾向于假设您的操作主要受CPU限制,因此它会使用一定程度的并行性来调整您的计算机具有多少CPU核心。但是HTTP请求往往是IO绑定的,因此大部分时间花在等待目标机器向您发送信息上。

这意味着这是一个使用异步处理的好机会。尝试这样的事情:

public async Task<string[]> getSplittedClassName()
{
    HttpResponseMessage response = await httpClient.GetAsync(url);
    return parser.breakdownClassName(response);
}

和此:

    var classNameTasks = Enumerable.Range(1, 200)
        .Select(i => webApi.getSplittedClassName())
        .ToArray();
    wordList.AddRange(
        Task.WhenAll(classNameTasks).Result
            .SelectMany(g => g));

说明:

  1. 使getSplittedClassName() 异步,以便不是同步获取所需的内容然后返回结果,而是立即返回Task<>,当结果为可用。
  2. 我删除了吃掉所有异常的代码,因为这通常是一种不好的做法。如果此处出现异常,您应该考虑一下您真正想做的事情:您是否应该重试该请求?只是抛出异常?忽略这样的问题通常是一个坏主意。
  3. Task.WhenAll()将返回Task<>,它将返回给定任务的所有结果。您可以同步等待所有这些任务完成,然后将它们全部添加到wordList作为批处理。这是线程安全的,因为所有项目都在一个线程上添加到wordList,而您的原始代码有多个线程可能同时尝试向wordList添加值。
  4. 另外,我假设这只是一项家庭作业,但如果这是一个真实的场景,那么你同时对同一个网址进行200次GET请求的事实就是一个大红旗。