2013-10-21 89 views
1

我有Webcrawles在C#中編寫,它使用多線程。現在它可以下載和解析約1000鏈接/分鐘,但是當我運行前。 3個實例同時每個實例可以達到1000個鏈接/分鐘,所以我有3000個鏈接/分鐘。一個實例使用高達2%的CPU,100MB RAM和1%的網絡速度。現在我想知道當我有可用的資源(cpu,ram,network)時,一個實例可能達到3000個鏈接/分鐘或更多?我的代碼c#Webcrawler優化

結構:

ThreadSafeFileBuffer<string> successWriter = new ThreadSafeFileBuffer<string>("ok.txt"); 
IEnumerable<string> lines = File.ReadLines("urls.txt"); 
var options = new ParallelOptions 
              { 
               CancellationToken = _cts.Token, 
               MaxDegreeOfParallelism = 500 
              }; 

Parallel.ForEach(lines, options, (line, loopState, idx) => 
               { 
var crawler = new Crawler(line); 
var result = crawler.Go(); //download,parse 
successWriter.AddResult(result); 
} 

我的Windows 7,CPU i7,16GB內存,SSD硬盤

+0

請注意,HEAD請求方法比GET方法快。適當時,您可以使用HEAD而不是GET。 – mecek

+1

@Mecek:HEAD確實比GET快,但通常不會太多。它取決於數據的大小。許多請求的主要部分不是傳輸數據的時間,而是請求和響應之間的延遲。另外,令人驚訝的數量的服務器爲HEAD請求返回404,或者返回與GET返回的頭不同的頭。當你添加正確處理404s的時間時,它幾乎成了一次洗滌。您最好始終使用GET,除非您知道對HEAD正確響應的那些網站。 –

回答

0

是的,它是。找出你的瓶頸在哪裏,並提高性能。

編輯:

如果您正在使用Parallel.ForEach,您可以使用ParallelOptions參數嘗試過載。設置MaxDegreeOfParallelism屬性可能會有所幫助。

+0

很難找到它:(我有簡單的Parallel.ForEach - 循環的每一個過程解析一個url - 它可能是線程限制的問題嗎? – ekapek

+0

已經這樣做,但具有較高的值 - 超過500的速度不會改變 – ekapek

0

在網絡爬蟲中,你將花費大部分時間等待網絡請求。所以如果你阻塞了I/O,你的程序將不會全速處理,如果程序處於空閒狀態等待回調,那麼異步IO也不會有幫助。聽起來就像你只需要添加更多的線程到你的主應用程序並行處理。

但是這很難說,因爲你還沒有發佈任何代碼,

0

實際上鍊接的數量/分是在同一時間運行履帶線程的數量成正比。

在您的第一個案例中;你有3個進程每個有n個線程。 (總共3n個線程)

嘗試在一個進程中運行3n個線程。

實際上這也取決於您的操作系統和CPU。因爲舊版本的Windows(如XP)不支持通過不同cpu核心進行並行多線程。

+0

我嘗試了500和1000與ForEach循環但是它不會改變速度 – ekapek

1

你不需要更多的線程,因爲那些線程都在等待。您需要一個異步程序,它不會阻止等待Web回覆的線程。

線程的問題在於它們是一個相當昂貴的資源,因爲它們的堆棧需要的內存以及它們爲OS線程調度程序創建的工作。在你的程序中,這個調度程序繼續切換線程,以便它們都可以輪流等待。但他們沒有做任何有用的事情。

+0

+1。更多的線程肯定是*不是*答案! –

3

在URL列表中使用Parallel.ForEach的問題是這些列表通常包含來自同一站點的許多URL,並且最終會對同一站點發出多個併發請求。有些網站對此不滿,並會阻止你或插入虛假延遲。

每分鐘1,000個請求每秒處理16或17個請求,這幾乎是您無需訴諸非常措施即可執行的限制。這個問題的很大一部分是DNS解析,這可能需要很長時間。另外,默認的.NET ServicePointManager將您限制爲任何給定站點上的2個併發請求。如果您想支持更多,則需要更改ServicePointManager.DefaultConnectionLimit屬性。

你肯定不想添加數百個線程。我曾經這樣做過。這是痛苦的。你需要的是少數線程可以非常快速地產生異步請求。我的測試表明,單個線程每秒不能維持超過15個請求,因爲HttpRequest.BeginGetResponse在執行異步之前會執行大量同步工作。如文檔所述:

在此方法變爲異步之前,BeginGetResponse方法需要完成一些同步設置任務(例如,DNS解析,代理檢測和TCP套接字連接)。

您可以通過增加DNS客戶端緩存的大小以及在單獨的計算機上使用本地DNS緩存來提高速度,但是您可以在其中實現某些限制。

我不知道你在做多少爬行。如果你做了很多事情,那麼你需要實施一個考慮到robots.txt文件的禮貌策略,限制它打到特定網站的頻率,限制它下載的URL類型(沒有必要下載MP3或者。例如doc文件,如果你不能做任何事情)等等。爲了防止你的抓取工具被阻止,抓取工具的核心是一個禮貌策略執行者,只是偶爾下載網頁。

我開始寫一些關於這段時間的文章,但後來沒有完成(其他項目優先)。查看第一篇文章的http://blog.mischel.com/2011/12/13/writing-a-web-crawler-introduction/,並鏈接到該主題中的其他帖子。另見http://blog.mischel.com/2011/12/26/writing-a-web-crawler-queue-management-part-1/。這是我一直想回到的東西,但近兩年後,我仍然沒有管理它。

你還會碰到proxy problems,URL過濾的問題(herehere),weird redirectsasynchronous calls that aren't completely asynchronous

+0

這個爬蟲博客很吸引人。幹得不錯! – Ryan

0

與TPL的並行性對於網絡爬蟲來說是不好的設計。一個Parallel.ForEach()循環僅啓動一堆請求(5-50),因爲它設計用於並行執行耗時的計算,而不是並行執行數千個請求,這些請求幾乎什麼也不做。要獲得您想要的數據,您必須能夠並行執行大量(10000+)以上的請求。異步操作是關鍵。

我開發了Crawler-Lib Framework的Crawler Engine。這是一個支持工作流的爬蟲程序,可以輕鬆擴展以執行任何類型的請求,甚至是您想要的處理。 它旨在爲您提供高開箱率。

這裏是發動機:http://www.crawler-lib.net/crawler-lib-engine

以下是一些YouTube視頻,顯示出履帶庫引擎是如何工作的:http://www.youtube.com/user/CrawlerLib

我知道這個項目是不開源的,但有一個免費版本。