HttpClient – 发送一批请求

我想迭代一批请求,使用HttpClient类将它们中的每一个发送到外部API。

foreach (var MyRequest in RequestsBatch) { try { HttpClient httpClient = new HttpClient(); httpClient.Timeout = TimeSpan.FromMilliseconds(5); HttpResponseMessage response = await httpClient.PostAsJsonAsync(string.Format("{0}api/GetResponse", endpoint), myRequest); JObject resultResponse = await response.Content.ReadAsAsync(); } catch (Exception ex) { continue; } } 

这里的上下文是我需要设置一个非常小的超时值,所以如果响应花费的时间超过了那个时间,我们只需得到“任务被取消”exception并继续迭代。

现在,在上面的代码中,注释这两行:

  HttpResponseMessage response = await httpClient.PostAsJsonAsync(string.Format("{0}api/GetResponse", endpoint), myRequest); resultResponse = await response.Content.ReadAsAsync(); 

迭代结束得非常快。 取消注释,然后重试。 这需要很多时间。

我想知道使用await调用PostAsJsonAsync / ReadAsAsync方法是否需要比超时值更多的时间?

根据下面的答案,假设它将创建不同的线程,我们有这个方法:

  public Task GetResponse(string endPoint, JObject request, TimeSpan timeout) { return Task.Run(async () => { try { HttpClient httpClient = new HttpClient(); httpClient.Timeout = TimeSpan.FromMilliseconds(5); HttpResponseMessage response = await httpClient.PostAsJsonAsync(string.Format("{0}api/GetResponse", endPoint), request).WithTimeout(timeout); JObject resultResponse = await response.Content.ReadAsAsync().WithTimeout(timeout); return resultResponse; } catch (Exception ex) { return new JObject() { new JProperty("ControlledException", "Invalid response. ")}; } }); } 

在那里引发exception并且应该非常快地返回JObjectexception,但是,如果使用httpClient方法,即使它引发exception也需要花费很多时间。 是否存在影响Task的幕后处理,即使返回值是一个简单的exceptionJObject?

如果是,可以使用哪种方法以非常快的方式向API发送一批请求?

看起来你实际上并没有为每个请求运行一个单独的线程。 尝试这样的事情:

 var taskList = new List>(); foreach (var myRequest in RequestsBatch) { taskList.Add(GetResponse(endPoint, myRequest)); } try { Task.WaitAll(taskList.ToArray()); } catch (Exception ex) { } public Task GetResponse(string endPoint, string myRequest) { return Task.Run(() => { HttpClient httpClient = new HttpClient(); HttpResponseMessage response = httpClient.PostAsJsonAsync( string.Format("{0}api/GetResponse", endpoint), myRequest, new CancellationTokenSource(TimeSpan.FromMilliseconds(5)).Token); JObject resultResponse = response.Content.ReadAsAsync(); }); } 

我同意接受的答案,因为加快速度的关键是并行运行请求。 但是任何通过使用Task.RunParallel.ForEach强制其他线程进入混合的解决方案都无法通过I / O绑定异步操作获得任何效率。 如果它有任何伤害。

您可以轻松地同时运行所有调用,同时让底层异步子系统决定尽可能高效地完成任务所需的线程数。 有可能这个数字远小于并发调用的数量,因为它们在等待响应时根本不需要任何线程。

此外,接受的答案为每个调用创建一个新的HttpClient实例。 不要那样做 – 坏事可能发生 。

以下是已接受答案的修改版本:

 var httpClient = new HttpClient { Timeout = TimeSpan.FromMilliseconds(5) }; var taskList = new List>(); foreach (var myRequest in RequestsBatch) { // by virtue of not awaiting each call, you've already acheived parallelism taskList.Add(GetResponseAsync(endPoint, myRequest)); } try { // asynchronously wait until all tasks are complete await Task.WhenAll(taskList.ToArray()); } catch (Exception ex) { } async Task GetResponseAsync(string endPoint, string myRequest) { // no Task.Run here! var response = await httpClient.PostAsJsonAsync( string.Format("{0}api/GetResponse", endpoint), myRequest); return await response.Content.ReadAsAsync(); }