Heim  >  Artikel  >  Backend-Entwicklung  >  Speicherverlust der HTML-Rendering-Funktion

Speicherverlust der HTML-Rendering-Funktion

王林
王林nach vorne
2024-02-06 10:39:11667Durchsuche

html 渲染函数内存泄漏

Frageninhalt

Das Problem, mit dem ich konfrontiert bin, besteht darin, dass selbst der Versuch von nur 200 Anfragen dazu führt, dass das Programm 6 GB des Speichers des Containers belegt und schließlich von oom beendet wird. Meine Idee ist, alle im HTML vorhandenen Textknoten zu extrahieren und sie dann zu verarbeiten, um ihren Namen, den HTML-Code und den Text dieses Tags zu extrahieren. Um also HTML für ein bestimmtes Tag zu generieren, verwende ich die Renderfunktion von golang.org/x/net/html. Wo ich strings.builder als io.writer bereitstelle, um den generierten HTML-Code zu schreiben. Aber aus irgendeinem Grund beansprucht der Builder zu viel Speicher.

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()
}

Wenn Sie eine bestimmte Liste von URLs wünschen, finden Sie sie hier. Ich habe ungefähr 60 Anfragen gleichzeitig gestellt.

Ich habe versucht, bytes.buffer bytes.buffer und sync.pool zu verwenden, aber beide haben das gleiche Problem. Bei der Verwendung von pprof ist mir aufgefallen, dass die writestring-Methode von strings.builder viel Speicher verbraucht. <code>bytes.buffersync.pool 但两者都有相同的问题。使用 pprof 我注意到 strings.builder 的 writestring 方法导致大量内存使用。


正确答案


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

Richtige Antwort

Das Grundproblem hier besteht also darin, jeden Inhaltstyp zu akzeptieren, der im Hinblick auf das Crawlen nicht akzeptabel ist, was die meisten Websites benötigen um text/html zu senden. golang.org/x/net/htmlDas Problem besteht darin, dass die

URL, selbst wenn sie

alles sendet, was keine HTML-Daten darstellt application/pdf ,然后正文将包含 html.Parse, diese dennoch akzeptiert, ohne einen Fehler auszulösen.

Nehmen wir ein Beispiel, bei dem die Binärdaten der analysierten PDF-Datei zurückgegeben werden und kein Fehler zurückgegeben wird. Dies ist eine seltsame Verhaltensgedankenbibliothek zum Scrapen/Crawlen, die Binärdaten akzeptiert.

🎜Die Lösung lautet: 🎜Überprüfen Sie die Antwortheader. Wenn nur die Daten HTML sind, fahren Sie fort, andernfalls kommt es zu Mehrdeutigkeiten oder einer höheren Speichernutzung (möglicherweise weniger), aber wir können nicht vorhersagen, was passieren wird. 🎜

Das obige ist der detaillierte Inhalt vonSpeicherverlust der HTML-Rendering-Funktion. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen