HttpClient - 发送一批请求
HttpClient - Send a batch of requests
我想迭代一批请求,使用 HttpClient class.
将每个请求发送到外部 API
foreach (var MyRequest in RequestsBatch)
{
try
{
HttpClient httpClient = new HttpClient();
httpClient.Timeout = TimeSpan.FromMilliseconds(5);
HttpResponseMessage response = await httpClient.PostAsJsonAsync<string>(string.Format("{0}api/GetResponse", endpoint), myRequest);
JObject resultResponse = await response.Content.ReadAsAsync<JObject>();
}
catch (Exception ex)
{
continue;
}
}
这里的上下文是我需要设置一个非常小的超时值,所以如果响应花费的时间超过那个时间,我们只需得到 "Task was cancelled" 异常并继续迭代。
现在,在上面的代码中,注释这两行:
HttpResponseMessage response = await httpClient.PostAsJsonAsync<string>(string.Format("{0}api/GetResponse", endpoint), myRequest);
resultResponse = await response.Content.ReadAsAsync<JObject>();
迭代结束得非常快。取消注释并重试。这需要很多时间。
我想知道使用 await 调用 PostAsJsonAsync/ReadAsAsync 方法是否需要比超时值更多的时间?
根据下面的答案,假设它会创建不同的线程,我们有这个方法:
public Task<JObject> 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>(string.Format("{0}api/GetResponse", endPoint), request).WithTimeout<HttpResponseMessage>(timeout);
JObject resultResponse = await response.Content.ReadAsAsync<JObject>().WithTimeout<JObject>(timeout);
return resultResponse;
}
catch (Exception ex)
{
return new JObject() { new JProperty("ControlledException", "Invalid response. ")};
}
});
}
那里引发了一个异常,JObject 异常应该被 returned,非常快,但是,如果使用 httpClient 方法,即使它引发异常也需要很多时间。即使 return 值是一个简单的异常 JObject,是否存在影响任务的幕后处理?
如果是,可以使用另一种方法以非常快的方式向 API 发送一批请求?
看起来您实际上 运行 每个请求都不是一个单独的线程。尝试这样的事情:
var taskList = new List<Task<JObject>>();
foreach (var myRequest in RequestsBatch)
{
taskList.Add(GetResponse(endPoint, myRequest));
}
try
{
Task.WaitAll(taskList.ToArray());
}
catch (Exception ex)
{
}
public Task<JObject> GetResponse(string endPoint, string myRequest)
{
return Task.Run(() =>
{
HttpClient httpClient = new HttpClient();
HttpResponseMessage response = httpClient.PostAsJsonAsync<string>(
string.Format("{0}api/GetResponse", endpoint),
myRequest,
new CancellationTokenSource(TimeSpan.FromMilliseconds(5)).Token);
JObject resultResponse = response.Content.ReadAsAsync<JObject>();
});
}
我同意接受的答案,因为加快速度的关键是 运行 并行请求。但是任何通过使用 Task.Run
或 Parallel.ForEach
强制额外线程混合的解决方案都不会通过 I/O 绑定异步操作获得任何效率。如果有什么是伤害的话。
您可以轻松地并发调用所有 运行ning,同时让底层异步子系统决定尽可能高效地完成任务需要多少线程。有可能这个数字远小于并发调用的数量,因为它们在等待响应时根本不需要任何线程。
此外,接受的答案会为每个调用创建一个新的 HttpClient
实例。也不要这样做 - bad things can happen.
这是已接受答案的修改版本:
var httpClient = new HttpClient {
Timeout = TimeSpan.FromMilliseconds(5)
};
var taskList = new List<Task<JObject>>();
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<JObject> GetResponseAsync(string endPoint, string myRequest)
{
// no Task.Run here!
var response = await httpClient.PostAsJsonAsync<string>(
string.Format("{0}api/GetResponse", endpoint),
myRequest);
return await response.Content.ReadAsAsync<JObject>();
}
我想迭代一批请求,使用 HttpClient class.
将每个请求发送到外部 API foreach (var MyRequest in RequestsBatch)
{
try
{
HttpClient httpClient = new HttpClient();
httpClient.Timeout = TimeSpan.FromMilliseconds(5);
HttpResponseMessage response = await httpClient.PostAsJsonAsync<string>(string.Format("{0}api/GetResponse", endpoint), myRequest);
JObject resultResponse = await response.Content.ReadAsAsync<JObject>();
}
catch (Exception ex)
{
continue;
}
}
这里的上下文是我需要设置一个非常小的超时值,所以如果响应花费的时间超过那个时间,我们只需得到 "Task was cancelled" 异常并继续迭代。
现在,在上面的代码中,注释这两行:
HttpResponseMessage response = await httpClient.PostAsJsonAsync<string>(string.Format("{0}api/GetResponse", endpoint), myRequest);
resultResponse = await response.Content.ReadAsAsync<JObject>();
迭代结束得非常快。取消注释并重试。这需要很多时间。
我想知道使用 await 调用 PostAsJsonAsync/ReadAsAsync 方法是否需要比超时值更多的时间?
根据下面的答案,假设它会创建不同的线程,我们有这个方法:
public Task<JObject> 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>(string.Format("{0}api/GetResponse", endPoint), request).WithTimeout<HttpResponseMessage>(timeout);
JObject resultResponse = await response.Content.ReadAsAsync<JObject>().WithTimeout<JObject>(timeout);
return resultResponse;
}
catch (Exception ex)
{
return new JObject() { new JProperty("ControlledException", "Invalid response. ")};
}
});
}
那里引发了一个异常,JObject 异常应该被 returned,非常快,但是,如果使用 httpClient 方法,即使它引发异常也需要很多时间。即使 return 值是一个简单的异常 JObject,是否存在影响任务的幕后处理?
如果是,可以使用另一种方法以非常快的方式向 API 发送一批请求?
看起来您实际上 运行 每个请求都不是一个单独的线程。尝试这样的事情:
var taskList = new List<Task<JObject>>();
foreach (var myRequest in RequestsBatch)
{
taskList.Add(GetResponse(endPoint, myRequest));
}
try
{
Task.WaitAll(taskList.ToArray());
}
catch (Exception ex)
{
}
public Task<JObject> GetResponse(string endPoint, string myRequest)
{
return Task.Run(() =>
{
HttpClient httpClient = new HttpClient();
HttpResponseMessage response = httpClient.PostAsJsonAsync<string>(
string.Format("{0}api/GetResponse", endpoint),
myRequest,
new CancellationTokenSource(TimeSpan.FromMilliseconds(5)).Token);
JObject resultResponse = response.Content.ReadAsAsync<JObject>();
});
}
我同意接受的答案,因为加快速度的关键是 运行 并行请求。但是任何通过使用 Task.Run
或 Parallel.ForEach
强制额外线程混合的解决方案都不会通过 I/O 绑定异步操作获得任何效率。如果有什么是伤害的话。
您可以轻松地并发调用所有 运行ning,同时让底层异步子系统决定尽可能高效地完成任务需要多少线程。有可能这个数字远小于并发调用的数量,因为它们在等待响应时根本不需要任何线程。
此外,接受的答案会为每个调用创建一个新的 HttpClient
实例。也不要这样做 - bad things can happen.
这是已接受答案的修改版本:
var httpClient = new HttpClient {
Timeout = TimeSpan.FromMilliseconds(5)
};
var taskList = new List<Task<JObject>>();
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<JObject> GetResponseAsync(string endPoint, string myRequest)
{
// no Task.Run here!
var response = await httpClient.PostAsJsonAsync<string>(
string.Format("{0}api/GetResponse", endpoint),
myRequest);
return await response.Content.ReadAsAsync<JObject>();
}