在 .net 4.0 中并行化 Web 爬网程序的最佳实践
本文关键字:程序 最佳 Web net 并行化 | 更新日期: 2023-09-27 18:34:55
我需要通过代理下载很多页面。构建多线程网络爬虫的最佳实践是什么?
Parallel.For''Foreach 是否足够好,或者对于繁重的 CPU 任务更好?
你怎么说下面的代码?
var multyProxy = new MultyProxy();
multyProxy.LoadProxyList();
Task[] taskArray = new Task[1000];
for(int i = 0; i < taskArray.Length; i++)
{
taskArray[i] = new Task( (obj) =>
{
multyProxy.GetPage((string)obj);
},
(object)"http://google.com"
);
taskArray[i].Start();
}
Task.WaitAll(taskArray);
它的工作非常糟糕。它非常慢,我不知道为什么。
此代码也工作不好。
System.Threading.Tasks.Parallel.For(0,1000, new System.Threading.Tasks.ParallelOptions(){MaxDegreeOfParallelism=30},loop =>
{
multyProxy.GetPage("http://google.com");
}
);
好吧,我认为我做错了什么。
当我启动脚本时,它仅以 2%-4% 的速度使用网络。
您基本上正在为IO绑定任务使用CPU绑定线程 - 即,即使您正在并行化操作,它们仍然基本上使用了一个ThreadPool线程,该线程主要用于CPU绑定操作。
基本上,您需要使用异步模式来下载数据以将其更改为使用IO完成端口 - 如果您使用的是WebRequest,则使用BeginGetResponse((和EndGetResponse((方法。
我建议查看反应式扩展来执行此操作,例如:
IEnumerable<string> urls = ... get your urls here...;
var results = from url in urls.ToObservable()
let req = WebRequest.Create(url)
from rsp in Observable.FromAsyncPattern<WebResponse>(
req.BeginGetResponse, req.EndGetResponse)()
select ExtractResponse(rsp);
其中ExtractResponse可能只使用StreamReader.ReadToEnd来获取字符串结果,如果这是你想要的。
您还可以查看使用 .重试运算符,然后,如果您遇到连接问题等,这将轻松允许您重试几次......
在
main 方法的开头添加以下内容:
System.Net.ServicePointManager.DefaultConnectionLimit = 100;
因此,您不会局限于少量的并发连接。
当您使用大量连接(添加到 app.config 或 web.config(时,这可能会对您有所帮助:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.net>
<connectionManagement>
<add address="*" maxconnection="50"/>
</connectionManagement>
</system.net>
</configuration>
设置并发连接数,而不是 50
个在 http://msdn.microsoft.com/en-us/library/fb6y0fyc.aspx 阅读更多相关信息