我正在構建一個抓取器,它需要一個URL,從中提取鏈接,並將它們中的每一個訪問到一定深度;在特定的網站上製作路徑樹。處理「打開文件過多」的最佳方法是什麼?
我實現並行這個爬蟲的方式是,我儘快訪問每個新發現的URL,因爲它的發現是這樣的:
func main() {
link := "https://example.com"
wg := new(sync.WaitGroup)
wg.Add(1)
q := make(chan string)
go deduplicate(q, wg)
q <- link
wg.Wait()
}
func deduplicate(ch chan string, wg *sync.WaitGroup) {
for link := range ch {
// seen is a global variable that holds all seen URLs
if seen[link] {
wg.Done()
continue
}
seen[link] = true
go crawl(link, ch, wg)
}
}
func crawl(link string, q chan string, wg *sync.WaitGroup) {
// handle the link and create a variable "links" containing the links found inside the page
wg.Add(len(links))
for _, l := range links {
q <- l}
}
}
這對於相對較小的站點工作正常,但是當我在一個運行大的鏈接到處都有很多鏈接,我開始在一些請求中獲得這兩個錯誤中的一個:socket: too many open files
和no such host
(主機確實存在)。
處理這個問題的最佳方法是什麼?我是否應該檢查這些錯誤並暫停執行,直到其他請求完成爲止?或者在特定時間指定可能請求的最大數量? (這對我更有意義,但不知道如何精確地編碼)
您正面臨與操作系統控制的每個用戶打開文件的限制有關的問題。如果您使用Linux/Unix,則可以使用ulimit -n 4096命令來增加限制。該命令有一個閾值,它不能設置你想要打開的文件的數量。所以如果你想進一步推動它,那麼你需要修改/etc/security/limits.conf文件並設置硬性限制和軟限制。 –
另外,你正在爲每個環節啓動一個配置程序,如果存在的話,那麼在某些時候它們中的許多人會失敗goroutines的目的,而且實際上需要更長的時間才能完成任務。你應該嘗試使用固定數量的goroutine來完成處理並從頻道讀取,而不是爲每個鏈接啓動一個新的。看看https://blog.golang.org/pipelines – Topo
或者可能是這樣的模式:https://gobyexample.com/worker-pools? (順便說一下,你的'WaitGroup'的用法很奇怪,爲每個goroutine加1,並且在每個goroutine中延遲'Done'。其他任何東西都是要求bug的) – JimB