C# 异步和任务
本文关键字:任务 异步 | 更新日期: 2023-09-27 18:35:12
我有一个函数,可以发送请求以从URL搜索信息。搜索条件是一个列表,搜索循环访问每个项目并从 URL 请求信息。为了加快速度,我将列表划分为 x 个子集,并为每个子集创建一个任务。然后每个子集同时发送 3 个请求,如下所示:
这是主要入口点:
Search search = new Search();
await Task.Run(() => search.Start());
启动功能:
public void Search()
{
//Each subset is a List<T> ie where T is certain search criteria
//If originalList.Count = 30 and max items per subset is 10, then subsets will be 3 lists of 10 items each
var subsets = CreateSubsets(originalList);
List<Task> tasks = new List<Task>(subsets.Count);
for (int i = 0; i < subsets.Count; i++)
tasks.Add(Task.Factory.StartNew(() => SearchSubset(subsets[i]));
Task.WaitAll(tasks.ToArray());
foreach (Task task in tasks)
if (task != null)
task.Dispose();
}
private void SearchSubset(List<SearchCriteria> subset)
{
//Checking that i+1 and i+2 is within subset.Count-1 has been omitted
for (int i = 0; i < subset.Count; i+=3)
{
Task[] tasks = {Task.Factory.StartNew(() => SearchCriteria(subset[i])),
Task.Factory.StartNew(() => SearchCriteria(subset[i+1])),
Task.Factory.StartNew(() => SearchCriteria(subset[i+2]))};
//Wait & dispose like above
}
}
private void SearchCriteria(SearchCriteria criteria)
{
//SearchForCriteria uses WebRequest and WebResponse (callback)
//to query the url and return the response.content
var results = SearchForCriteria(criteria);
//process results...
}
上面的代码工作正常,搜索速度非常快。但是,上面的代码是否会产生太多的开销,是否有更干净(或更简单)的方法来实现相同的结果?
这不是最有效的方法,但如果这是针对桌面应用程序,那么效率无论如何都不是您主要关注的问题。因此,除非您确实看到此代码导致性能下降,否则不应更改它。
也就是说,我会以不同的方式处理这个问题。
你正在使用 TPL 并行化 I/O 绑定操作。您正在使用动态并行性,这是最复杂的类型;正如 Jeff Mercado 所评论的那样,如果您使用更高级别的并行抽象(如 Parallel
或 PLINQ
),您的代码会更简单、效率更高。
但是,任何并行方法都会通过阻塞线程池线程来浪费线程池线程。由于这是 I/O 绑定的,我建议使用 async
/await
使它们并发。
如果要执行简单的限制,可以使用SemaphoreSlim
。我认为除了子集之外,您不需要像这样进行限制,但是如果您想要一个与现有代码等效的async
,它看起来像这样:
public Task SearchAsync()
{
var subsets = CreateSubsets(originalList);
return Task.WhenAll(subsets.Select(subset => SearchSubsetAsync(subset)));
}
private Task SearchSubsetAsync(List<SearchCriteria> subset)
{
var semaphore = new SemaphoreSlim(3);
return Task.WhenAll(subset.Select(criteria => SearchCriteriaAsync(criteria, semaphore)));
}
private async Task SearchCriteriaAsync(SearchCriteria criteria, SemaphoreSlim semaphore)
{
await semaphore.WaitAsync();
try
{
// SearchForCriteriaAsync uses HttpClient (async).
var results = await SearchForCriteriaAsync(criteria);
// Consider returning results rather than processing them here.
}
finally
{
semaphore.Release();
}
}