0

我有一个发送请求以从 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...
}

上面的代码工作正常,搜索速度非常快。但是,上面的代码是否会产生过多的开销,是否有更清洁(或更简单)的方法来实现相同的结果?

4

1 回答 1

0

这不是最有效的方法,但如果这是用于桌面应用程序,那么效率无论如何都不是您最关心的问题。因此,除非您实际看到此代码的性能下降,否则不应更改它。

也就是说,我会以不同的方式处理这个问题。

您正在使用 TPL 来并行化 I/O 绑定操作。您正在使用最复杂的动态并行Parallel正如 Jeff Mercado 评论的那样,如果您使用更高级别的并行抽象,例如orPLINQ,您的代码会更简单,效率更高。

但是,任何并行方法都会通过阻塞线程池线程来浪费它们。由于这是 I/O-bound,我建议使用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();
  }
}
于 2013-10-13T15:33:50.670 回答