我有一个 Web API 方法,它接受字符串列表,对每个字符串执行 Web 请求,并将所有数据编译到一个列表中以供返回。
输入列表的长度可以是可变的,最多可达数千个。我是否需要通过将并发任务分组来手动限制并发任务的数量,或者创建数千个任务并使用
Task.WhenAll()
等待它们是否安全?这是我现在使用的片段:
public async Task<List<Customer>> GetDashboard(List<string> customerIds)
{
HttpClient client = new HttpClient();
var tasks = new List<Task>();
var customers = new List<Customer>();
foreach (var customerId in customerIds)
{
string customerIdCopy = customerId;
tasks.Add(client.GetStringAsync("http://testurl.com/" + customerId)
.ContinueWith(t => {
customers.Add(new Customer { Id = customerIdCopy, Data = t.Result });
}));
}
await Task.WhenAll(tasks);
return customers;
}
HttpClient
可以有效地执行并发请求,但需要注意的是它限制了单个服务器的并发请求数量。
如果您的请求全部发送到同一个站点,则多余的请求将被放入队列中。当请求在此队列中时,请求超时会逐渐减少......在尝试连接到服务器之前。因此,请小心管理,如果合适的话甚至可以关闭超时。
除此之外,一次发起数千个请求也是完全可以的。
SemaphoreSlim
或 TPL 数据流来限制并发请求的数量。
首先想到的是将所有“多线程性能”部分委托给 TPL。在您的请求中使用
async
,而不是手动创建的任务和 ContinueWith
。private async Task<Customer> GetDashboardAsync(string customerId)
{
using (var httpClient = new HttpClient())
{
string data = await httpClient.GetStringAsync("http://testurl.com/" + id);
return new Customer { Id = id, Data = data });
}
}
public async Task<Customer[]> GetDashboardAsync(List<string> customerIds)
{
var tasks = customerIds
.Select(GetDashboardAsync)
.ToArray();
return await Task.WhenAll(tasks);
}
我是否需要通过将并发任务分组来手动限制并发任务的数量,或者创建数千个任务并使用
等待它们是否安全?Task.WhenAll()
如果您仅使用
List
、foreach
和 ContinueWith
创建任务,则可能会因任务数量过多而导致性能下降。async/await
,那么您就不需要担心它。 TPL 将使用异步任务和延续来提供最佳性能。