使用“template”包在Golang中向客户端生成动态网页时,花费的时间太长了。

huangapple go评论82阅读模式
英文:

It takes too much time when using "template" package to generate a dynamic web page to client in Golang

问题

使用template包生成动态网页发送给客户端时,速度非常慢。

以下是测试代码,使用的是golang 1.4.1版本:

http.Handle("/js/", (http.FileServer(http.Dir(webpath))))
http.Handle("/css/", (http.FileServer(http.Dir(webpath))))
http.Handle("/img/", (http.FileServer(http.Dir(webpath))))
http.HandleFunc("/test", TestHandler)

func TestHandler(w http.ResponseWriter, r *http.Request) {
    Log.Info("Entering TestHandler ...")
    r.ParseForm()

    filename := NiConfig.webpath + "/test.html"

    t, err := template.ParseFiles(filename)
    if err != nil {
        Log.Error("template.ParseFiles err = %v", err)
    }

    t.Execute(w, nil)
}

根据日志,我发现在t.Execute(w, nil)这一行大约花费了3秒的时间,我不知道为什么会花费这么长的时间。我还尝试了使用Apache服务器测试test.html,它的响应非常快。

英文:

It is so slow when using template package to generate a dynamic web page to client.

Testing code as below, golang 1.4.1

http.Handle("/js/", (http.FileServer(http.Dir(webpath))))
http.Handle("/css/", (http.FileServer(http.Dir(webpath))))
http.Handle("/img/", (http.FileServer(http.Dir(webpath))))
http.HandleFunc("/test", TestHandler)


func TestHandler(w http.ResponseWriter, r *http.Request) {

	Log.Info("Entering TestHandler ...")
	r.ParseForm()

	filename := NiConfig.webpath + "/test.html"
	
	t, err := template.ParseFiles(filename)
	if err != nil {
		Log.Error("template.ParseFiles err = %v", err)
	} 
	
	t.Execute(w, nil)
}

According to the log, I found that it took about 3 seconds in t.Execute(w, nil), I do not know why it uses so much time. I also tried Apache server to test test.html, it responded very fast.

答案1

得分: 17

每次提供请求时,你不应该解析模板!

读取文件、解析内容和构建模板都需要花费相当长的时间。而且,由于模板不会改变(变化的部分应该是参数!),你只需要读取和解析一次模板即可。此外,每次提供请求时解析和创建模板会在内存中生成大量的值,然后被丢弃(因为它们不会被重用),这给垃圾回收器增加了额外的工作量。

在应用程序启动时解析模板,将其存储在一个变量中,只有在请求到达时才执行模板。例如:

var t *template.Template

func init() {
	filename := NiConfig.webpath + "/test.html"
	t = template.Must(template.ParseFiles(filename))
	
	http.HandleFunc("/test", TestHandler)
}

func TestHandler(w http.ResponseWriter, r *http.Request) {
    Log.Info("进入TestHandler...")
    // 模板已准备好,只需执行它
    if err := t.Execute(w, nil); err != nil {
        log.Printf("无法执行模板:%v", err)
    }
}
英文:

You should not parse templates every time you serve a request!

There is a significant time delay to read a file, parse its content and build the template. Also since templates do not change (varying parts should be parameters!) you only have to read and parse a template once.
Also parsing and creating the template each time when serving a request generates lots of values in memory which are then thrown away (because they are not reused) giving additional work for the garbage collector.

Parse the templates when your application starts, store it in a variable, and you only have to execute the template when a request comes in. For example:

var t *template.Template

func init() {
	filename := NiConfig.webpath + "/test.html"
	t = template.Must(template.ParseFiles(filename))
	
	http.HandleFunc("/test", TestHandler)
}

func TestHandler(w http.ResponseWriter, r *http.Request) {
    Log.Info("Entering TestHandler ...")
    // Template is ready, just Execute it
    if err := t.Execute(w, nil); err != nil {
        log.Printf("Failed to execute template: %v", err)
    }
}

huangapple
  • 本文由 发表于 2015年2月11日 18:15:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/28451675.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定