4

我有大量显示状态的网页列表,我需要对其进行检查。一些 url 在同一个站点内,另一组位于另一个站点上。

现在我正在尝试通过使用下面的代码以并行方式执行此操作,但我觉得我造成了太多开销。

while(ListOfUrls.Count > 0){
  Parallel.ForEach(ListOfUrls, url =>
  {
    WebClient webClient = new WebClient();
    webClient.DownloadString(url);
    ... run my checks here.. 
  });

  ListOfUrls = GetNewUrls.....
}

这可以用更少的开销来完成,并且可以对我使用/重用多少网络客户端和连接进行更多控制吗?那么,那到底这项工作可以完成得更快吗?

4

4 回答 4

7

Parallel.ForEachDownloadString对 CPU 密集型计算任务很有用,但对于像您的情况一样,同步 IO 密集型调用将不需要阻塞池线程。DownloadStringTaskAsync您可以通过使用and 任务来提高代码的可伸缩性并减少它可能使用的线程数:

// non-blocking async method
async Task<string> ProcessUrlAsync(string url)
{
    using (var webClient = new WebClient())
    {
        string data = await webClient.DownloadStringTaskAsync(new Uri(url));
        // run checks here.. 
        return data;
    }
}

// ...

if (ListOfUrls.Count > 0) {
    var tasks = new List<Task>();
    foreach (var url in ListOfUrls)
    {
      tasks.Add(ProcessUrlAsync(url));
    }

    Task.WaitAll(tasks.ToArray()); // blocking wait

    // could use await here and make this method async:
    // await Task.WhenAll(tasks.ToArray());
}
于 2013-10-15T21:21:33.503 回答
1

您可以尝试在 .Net 4.5 中使用新添加的 HttpClient,它认为速度更快,并且可能会稍微提高您的性能

using (HttpClient client = new HttpClient())
using (HttpResponseMessage response = await client.GetAsync(url))
using (HttpContent content = response.Content)
{

    string result = await content.ReadAsStringAsync();


}
于 2013-10-15T20:06:31.393 回答
0

应用程序的 web.config 或 app.config 文件中经常被忽视的元素是 connectionManagement 标记。特别是,.NET 默认将同时连接到域的数量限制为 2。您可以在此处查看标签的文档。

如果我正确理解了您的问题,那么默认情况下,将并行创建到 2 个域的 Web 客户端将限制为 4 个线程(每个域 2 个线程),从而导致速度低于您的预期。

但是,如果您要连接到多个域,那么其他答案可能会产生更多的加速,因为等待响应可能是每个循环迭代成本的很大一部分。如果您使用的是 .NET 4.5,GetStringAsync则方法可能是您的朋友。

于 2013-10-15T21:46:07.790 回答
-1

您是否考虑过代码的异步执行?我认为没有更快的方法从 Internet 获取数据,但您可以同时进行。

于 2013-10-15T20:02:46.467 回答