C# - 执行200个http get请求并输出结果
C# - executing 200 http get requests and output the results
我有一个控制台应用程序,用户可以在其中输入菜单选项 (1-5),我执行一些功能并输出结果。
其中一个功能是对某些 url 执行 200 个 http get 请求,获取所有结果,对其进行一些处理并输出给用户。
这是我当前的代码:
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);
}
现在,由于用户输入了一个选项编号,程序执行了所需的功能,然后我输入了输出,我认为异步执行 http 工作没有意义,所以它都是同步的。
问题是处理请求需要很多时间,大约 30-40 秒..这有意义吗?
基本上有3个特征:做1个请求,做3个请求和200个请求。
执行 200 个请求并等待所有结果的最佳选择是什么?是不是应该像我只发出一个请求那样同步?
谢谢
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));
解释:
- 使
getSplittedClassName()
async 这样就不会同步获取所需的东西然后 returning 结果,而是立即 return s 一个 Task<>
将在结果可用时完成。
- 我删除了吃掉所有异常的代码,因为这通常是一种不好的做法。如果这里出现异常,您应该考虑您真正想要做什么:您是否应该重试该请求?只是让异常被抛出?忽略这样的问题通常是个坏主意。
Task.WhenAll()
将 return 一个 Task<>
将 return 给定任务的所有结果。您可以同步等待所有这些任务完成,然后将它们作为批处理全部添加到 wordList
。这是线程安全的,因为所有项目都在单个线程上添加到 wordList
,而您的原始代码有多个线程可能会同时尝试将值添加到 wordList
。
此外,我假设这只是一项家庭作业,但如果这是真实场景,那么您同时对同一个 URL 执行 200 个 GET 请求这一事实将是一个大危险信号。
我有一个控制台应用程序,用户可以在其中输入菜单选项 (1-5),我执行一些功能并输出结果。
其中一个功能是对某些 url 执行 200 个 http get 请求,获取所有结果,对其进行一些处理并输出给用户。
这是我当前的代码:
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);
}
现在,由于用户输入了一个选项编号,程序执行了所需的功能,然后我输入了输出,我认为异步执行 http 工作没有意义,所以它都是同步的。
问题是处理请求需要很多时间,大约 30-40 秒..这有意义吗?
基本上有3个特征:做1个请求,做3个请求和200个请求。
执行 200 个请求并等待所有结果的最佳选择是什么?是不是应该像我只发出一个请求那样同步?
谢谢
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));
解释:
- 使
getSplittedClassName()
async 这样就不会同步获取所需的东西然后 returning 结果,而是立即 return s 一个Task<>
将在结果可用时完成。 - 我删除了吃掉所有异常的代码,因为这通常是一种不好的做法。如果这里出现异常,您应该考虑您真正想要做什么:您是否应该重试该请求?只是让异常被抛出?忽略这样的问题通常是个坏主意。
Task.WhenAll()
将 return 一个Task<>
将 return 给定任务的所有结果。您可以同步等待所有这些任务完成,然后将它们作为批处理全部添加到wordList
。这是线程安全的,因为所有项目都在单个线程上添加到wordList
,而您的原始代码有多个线程可能会同时尝试将值添加到wordList
。
此外,我假设这只是一项家庭作业,但如果这是真实场景,那么您同时对同一个 URL 执行 200 个 GET 请求这一事实将是一个大危险信号。