【发布时间】:2018-03-07 12:52:55
【问题描述】:
我正在尝试用 go 重写一个网络爬虫(最初是用 python 和 gevent 编写的)。但是我碰壁了,无论我做什么,我都会快速消耗大量内存。例如下面的简单代码:
package main
import (
"bufio"
"fmt"
"os"
"net/http"
"io"
"strings"
"time"
)
func readLine(in *bufio.Reader, domains chan<- string) {
for conc := 0; conc < 500; conc++ {
input, err := in.ReadString('\n')
if err == io.EOF {
break
}
if err != nil {
fmt.Fprintf(os.Stderr, "read(stdin): %s\n", err)
os.Exit(1)
}
input = strings.TrimSpace(input)
if input == "" {
continue
}
domain := input
domains <- domain
}
}
func get(domains <-chan string) {
url := <-domains
URLresp, err := http.Get(url)
if err != nil {
fmt.Println(err)
}
if err == nil {
fmt.Println(url," OK")
URLresp.Body.Close()
}
}
func main() {
domains := make(chan string, 500)
inFile, _ := os.Open("F:\\PATH\\TO\\LIST_OF_URLS_SEPARATED_BY_NEWLINE.txt")
in := bufio.NewReader(inFile)
for {
go readLine(in, domains)
for i := 0; i < 500; i++ { go get(domains) }
time.Sleep(100000000)
}
}
我尝试过 pprof,但似乎说我只使用了 50mb 的堆空间,而资源监控的内存消耗正在飙升。
我还尝试在不使用 Keep Alive 的情况下创建自定义 http 传输,因为我发现 net/http 保存连接以供重用,但没有运气。
【问题讨论】:
-
你在“无休止地”产生 goroutines(睡眠只有 0.1 秒)。您还在不同步的情况下同时使用
in,并且您的所有readLine()函数都从同一个文件中读取,未同步。而且您不检查打开文件的错误。没有什么好的结果。 -
您的代码充满了错误。最灾难的一个是有效的分叉炸弹。您正在启动无数个在您的域中读取的 goroutine。
-
如果你想重用连接,你需要阅读响应正文。如果您不需要重用连接,则应关闭它们以尽快释放资源。
-
您需要管理生成的 goroutine 的数量 - 请参阅此处 gobyexample.com/worker-pools
标签: go web-crawler