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

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

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

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

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

Parallel.ForEach适用于CPU绑定的计算任务,但在您的情况下,它将不必要用于同步IO绑定调用(如DownloadString池池线程。 通过使用DownloadStringTaskAsync和任务,您可以提高代码的可伸缩性并减少可能使用的线程数:

 // non-blocking async method async Task 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(); 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()); } 

您可以尝试在.Net 4.5中使用HttpClient新增function,它认为速度更快,可能会提高您的性能

 using (HttpClient client = new HttpClient()) using (HttpResponseMessage response = await client.GetAsync(url)) using (HttpContent content = response.Content) { string result = await content.ReadAsStringAsync(); } 

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

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

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

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