Rumah >pembangunan bahagian belakang >Golang >kebocoran memori fungsi rendering html

kebocoran memori fungsi rendering html

王林
王林ke hadapan
2024-02-06 10:39:11683semak imbas

html 渲染函数内存泄漏

Kandungan soalan

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.buffersync.pool 但两者都有相同的问题。使用 pprof 我注意到 strings.builder 的 writestring 方法导致大量内存使用。


正确答案


所以这里的基本问题是接受任何 content-type ,这在抓取方面是不可接受的,大多数网站都需要发送 text/html

Jawapan Betul

Jadi isu asas di sini adalah untuk menerima sebarang jenis kandungan yang tidak boleh diterima dari segi merangkak, kebanyakan tapak web Semua memerlukan untuk menghantar text/html. golang.org/x/net/htmlMasalahnya ialah walaupun

url menghantar

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!

Kenyataan:
Artikel ini dikembalikan pada:stackoverflow.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam