Masalah yang saya hadapi ialah walaupun mencuba hanya 200 permintaan menyebabkan program itu menduduki 6gb memori kontena dan akhirnya dibunuh oleh oom. Idea saya adalah untuk mengekstrak semua nod teks yang terdapat dalam html dan kemudian memprosesnya untuk mengekstrak nama mereka, html dan teks teg itu. Jadi, untuk menjana html untuk teg tertentu, saya menggunakan fungsi render daripada golang.org/x/net/html. Di mana saya menyediakan strings.builder sebagai io.writer untuk menulis html yang dijana. Tetapi atas sebab tertentu pembina mengambil terlalu banyak ingatan.
package main import ( "encoding/csv" "io" "log" "net/http" "strings" "golang.org/x/net/html" ) func main() { mux := http.NewServeMux() mux.HandleFunc("/data", GetData) if err := http.ListenAndServe(":8001", mux); err != nil { log.Println(err) } } type TagInfo struct { Tag string Name string Text string } // http.handler func GetData(w http.ResponseWriter, r *http.Request) { u := r.URL.Query().Get("url") doc, err := GetDoc(u) if err != nil { log.Println(err) w.WriteHeader(500) return } var buf strings.Builder data := Extract(doc, &buf) csvw := csv.NewWriter(io.Discard) for _, d := range data { csvw.Write([]string{d.Name, d.Tag, d.Text}) } } // fires request and get text/html func GetDoc(u string) (*html.Node, error) { res, err := http.Get(u) if err != nil { return nil, err } defer res.Body.Close() return html.Parse(res.Body) } func Extract(doc *html.Node, buf *strings.Builder) []TagInfo { var ( tags = make([]TagInfo, 0, 100) f func(*html.Node) ) f = func(n *html.Node) { if n.Type == html.TextNode { text := strings.TrimSpace(n.Data) if text != "" { parent := n.Parent tag := Render(parent, buf) tagInfo := TagInfo{ Tag: tag, Name: parent.Data, Text: n.Data, } tags = append(tags, tagInfo) } } for child := n.FirstChild; child != nil; child = child.NextSibling { f(child) } } f(doc) return tags } // Render the html around the tag // if node is text then pass the // parent node paramter in function func Render(n *html.Node, buf *strings.Builder) string { defer buf.Reset() if err := html.Render(buf, n); err != nil { log.Println(err) return "" } return buf.String() }
Jika anda mahukan senarai URL yang khusus, ini dia. Saya membuat kira-kira 60 permintaan pada satu masa.
Saya cuba menggunakan bytes.buffer bytes.buffer
dan sync.pool
tetapi kedua-duanya mempunyai masalah yang sama. Menggunakan pprof
Saya mendapati bahawa kaedah writestring strings.builder menyebabkan banyak penggunaan memori. <code>bytes.buffer
和 sync.pool
但两者都有相同的问题。使用 pprof
我注意到 strings.builder 的 writestring
方法导致大量内存使用。
所以这里的基本问题是接受任何 content-type
,这在抓取方面是不可接受的,大多数网站都需要发送 text/html
Jadi isu asas di sini adalah untuk menerima sebarang text/html
. golang.org/x/net/html
Masalahnya ialah walaupun
apa sahaja yang tidak mewakili data html application/pdf
,然后正文将包含 html.Parse
ia masih menerimanya tanpa membuang ralat.
Mari kita ambil contoh di mana data binari pdf yang dihuraikan dikembalikan dan tiada ralat dikembalikan, ini adalah perpustakaan pemikiran tingkah laku yang pelik untuk mengikis/merangkak menerima data binari.
🎜Penyelesaian ialah: 🎜Periksa tajuk respons, jika hanya data adalah html, kemudian teruskan, jika tidak akan berlaku kekaburan atau penggunaan memori yang lebih tinggi (mungkin lebih rendah), tetapi kita tidak dapat meramalkan apa yang akan berlaku. 🎜Atas ialah kandungan terperinci kebocoran memori fungsi rendering html. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!