C#从巨大的网址列表中下载数据

时间:2013-10-15 19:59:09

标签: c# parallel-processing webclient parallel.foreach downloadstring

我有一个巨大的网页列表,显示状态,我需要检查。 一些网址位于同一网站内,另一个网址位于另一个网站上。

现在我正试图通过使用下面的代码以并行的方式做到这一点,但我感觉我造成了太多的开销。

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

  ListOfUrls = GetNewUrls.....
}

这可以用更少的开销完成,并且可以更多地控制我使用/重用的webclients和连接数量吗?那么,最终工作可以更快完成吗?

4 个答案:

答案 0 :(得分:6)

Parallel.ForEach适用于受CPU约束的计算任务,但在您的情况下,它将不必为像DownloadString这样的同步IO绑定调用阻塞池线程。您可以使用DownloadStringTaskAsync和任务来提高代码的可伸缩性并减少可能使用的线程数:

// 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());
}

答案 1 :(得分:2)

你可以尝试在.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();


}

答案 2 :(得分:0)

应用程序的web.config或app.config文件中经常被忽略的元素是connectionManagement标记。特别是,默认情况下,.NET会将同时连接到域的连接数限制为2。您可以看到标记here的文档。

如果我正确地理解了您的问题,那么默认情况下并行创建2个域的Web客户端将被限制为4个线程(每个域2个线程),导致加速比您预期的要少。

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

答案 3 :(得分:-1)

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