gpt4 book ai didi

go - Go 语言中 html/模板的性能缓慢,有什么解决方法吗?

转载 作者:IT老高 更新时间:2023-10-28 13:06:59 30 4
gpt4 key购买 nike

我在 Go 中对这种类型的代码进行压力测试(使用 loader.io),以创建一个包含 100 项的数组以及一些其他基本变量,并在模板中全部解析:

package main

import (
"html/template"
"net/http"
)

var templates map[string]*template.Template

// Load templates on program initialisation
func init() {
if templates == nil {
templates = make(map[string]*template.Template)
}

templates["index.html"] = template.Must(template.ParseFiles("index.html"))
}

func handler(w http.ResponseWriter, r *http.Request) {
type Post struct {
Id int
Title, Content string
}

var Posts [100]Post

// Fill posts
for i := 0; i < 100; i++ {
Posts[i] = Post{i, "Sample Title", "Lorem Ipsum Dolor Sit Amet"}
}

type Page struct {
Title, Subtitle string
Posts [100]Post
}

var p Page

p.Title = "Index Page of My Super Blog"
p.Subtitle = "A blog about everything"
p.Posts = Posts

tmpl := templates["index.html"]

tmpl.ExecuteTemplate(w, "index.html", p)
}

func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8888", nil)
}

我的 Loader 测试在 1 分钟内使用 5k 并发连接/秒。问题是,在开始测试几秒钟后,我得到了很高的平均延迟(几乎 10 秒),结果是 5k 成功响应,测试停止,因为它达到了 50% 的错误率(超时)。

在同一台机器上,PHP 给出 50k+。

我知道这不是 Go 性能问题,而可能与 html/template 相关。 Go 可以轻松地管理足够困难的计算,当然比 PHP 快得多,但是在将数据解析到模板时,为什么会如此糟糕?

任何解决方法,或者我可能只是做错了(我是 Go 新手)?

附:实际上,即使有 1 个项目,它也是完全相同的...... 5-6k 并在大量超时后停止。但这可能是因为包含帖子的数组保持相同的长度。

我的模板代码(index.html):

{{ .Title }}
{{ .Subtitle }}

{{ range .Posts }}
{{ .Title }}
{{ .Content }}
{{ end }}

这是 github.com/pkg/profile 的分析结果:

root@Test:~# go tool pprof app /tmp/profile311243501/cpu.pprof
Possible precedence issue with control flow operator at /usr/lib/go/pkg/tool/linux_amd64/pprof line 3008.
Welcome to pprof! For help, type 'help'.
(pprof) top10
Total: 2054 samples
97 4.7% 4.7% 726 35.3% reflect.Value.call
89 4.3% 9.1% 278 13.5% runtime.mallocgc
85 4.1% 13.2% 86 4.2% syscall.Syscall
66 3.2% 16.4% 75 3.7% runtime.MSpan_Sweep
58 2.8% 19.2% 1842 89.7% text/template.(*state).walk
54 2.6% 21.9% 928 45.2% text/template.(*state).evalCall
51 2.5% 24.3% 53 2.6% settype
47 2.3% 26.6% 47 2.3% runtime.stringiter2
44 2.1% 28.8% 149 7.3% runtime.makeslice
40 1.9% 30.7% 223 10.9% text/template.(*state).evalField

这些是改进代码后的分析结果(如 icza 的回答中所建议的那样):

root@Test:~# go tool pprof app /tmp/profile501566907/cpu.pprof
Possible precedence issue with control flow operator at /usr/lib/go/pkg/tool/linux_amd64/pprof line 3008.
Welcome to pprof! For help, type 'help'.
(pprof) top10
Total: 2811 samples
137 4.9% 4.9% 442 15.7% runtime.mallocgc
126 4.5% 9.4% 999 35.5% reflect.Value.call
113 4.0% 13.4% 115 4.1% syscall.Syscall
110 3.9% 17.3% 122 4.3% runtime.MSpan_Sweep
102 3.6% 20.9% 2561 91.1% text/template.(*state).walk
74 2.6% 23.6% 337 12.0% text/template.(*state).evalField
68 2.4% 26.0% 72 2.6% settype
66 2.3% 28.3% 1279 45.5% text/template.(*state).evalCall
65 2.3% 30.6% 226 8.0% runtime.makeslice
57 2.0% 32.7% 57 2.0% runtime.stringiter2
(pprof)

最佳答案

使用 html/template 的等效应用程序比 PHP 变体慢的主要原因有两个。

首先html/template 提供了比PHP 更多的功能。主要区别在于 html/template 将使用正确的转义规则(HTML、JS、CSS 等)自动转义变量,具体取决于它们在生成的 HTML 输出中的位置(我认为这很酷!) .

其次,html/template 渲染代码大量使用反射和具有可变数量参数的方法,它们只是不如静态编译的代码快。

下面的模板

{{ .Title }}
{{ .Subtitle }}

{{ range .Posts }}
{{ .Title }}
{{ .Content }}
{{ end }}

被转换成类似的东西

{{ .Title | html_template_htmlescaper }}
{{ .Subtitle | html_template_htmlescaper }}

{{ range .Posts }}
{{ .Title | html_template_htmlescaper }}
{{ .Content | html_template_htmlescaper }}
{{ end }}

在循环中使用反射调用 html_template_htmlescaper 会降低性能。

说了这么多,html/template的这个微基准不应该用来决定是否使用Go。一旦您将代码与数据库一起添加到请求处理程序中,我怀疑模板渲染时间几乎不会被注意到。

我也很确定,随着时间的推移,Go 反射和 html/template 包都会变得更快。

如果在实际应用程序中您会发现 html/template 是一个瓶颈,仍然可以切换到 text/template 并为其提供已经转义的数据。

关于go - Go 语言中 html/模板的性能缓慢,有什么解决方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31361745/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com