在Go语言中,是否有必要将模板放入地图中以便重用?

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

Is it necessary to put templates into a map for reusing in Go?

问题

为了处理Web应用程序中的每个请求,关于模板的正常代码如下:

t := template.New("welcome")
t, _ = t.ParseFiles("welcome.tpl")
t.Execute(w, data)

我猜每次ParseFiles都会花费很多时间。是否有可能重用模板?所以我改进了它,像这样:

//templateMap := make(map[string][template])
//...
tplName := "welcome"
t := templateMap[tplName]
if t == nil {
    t := template.New(tplName)
    t, _ = t.ParseFiles("welcome.tpl")
    templateMap[tplName] = t
}

t.Execute(w, data)

我想知道将模板放入映射或缓存中是否可行或可行?我还想知道Execute函数是否线程安全?

func (t *Template) Execute(wr io.Writer, data interface{}) (err error)

英文:

To deal with every request in a web application, the normal code about templates is like this:

t:= template.New("welcome")
t, _ = t.ParseFiles("welcome.tpl")
t.Execute(w, data)

I guess ParseFiles every time cost a lot. Is it possible to reuse the template? So I improved it like this:

//templateMap := make(map[string][template])
//...
tplName :="welcome"
t := templateMap[tplName]
if t=nil{
    t:= template.New(tplName )
    t, _ = t.ParseFiles("welcome.tpl")
    templateMap[tplName] = t
}

t.Execute(w, data)

I wonder it is feasible or practicable to improve efficiency by putting templates into a map or a cache?
I also wonder the function Execute is thread safe or not?

func (t *Template) Execute(wr io.Writer, data interface{}) (err error)

答案1

得分: 13

一个模板实际上可以作为一个模板映射。这是我做的:

我声明一个全局模板变量:

var t = template.New("master")

实际上我并不使用"master"模板,只是将其作为其他模板的容器。

然后,在我的应用程序启动时加载所有模板:

func init() {
    _, err := t.ParseGlob("templates/*.html")
    if err != nil {
        log.Fatalln("加载模板出错:", err)
    }
}

然后,当我想要使用其中一个模板时,我通过名称请求它:

t.ExecuteTemplate(w, "user.html", data)
英文:

A template can actually act as a map of templates by itself. Here's what I do:

I declare a global template variable:

var t = template.New("master")

I don't actually use the "master" template, except as a container for other templates.

Then, I load all the templates when my app starts:

func init() {
    _, err := t.ParseGlob("templates/*.html")
    if err != nil {
        log.Fatalln("Error loading templates:", err)
    }
}

Then when I want to use one of the templates, I ask for it by name:

t.ExecuteTemplate(w, "user.html", data)

答案2

得分: 0

从template.go的源代码中,Execute函数使用了一个锁,我是一个新手,它看起来是线程安全的,但如果将模板实例放入一个映射中并尝试重用它,可能效率不高,如果你需要处理大量并发请求:

func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
        t.nameSpace.mu.Lock()
        if !t.escaped {
                if err = escapeTemplates(t, t.Name()); err != nil {
                        t.escaped = true
                }
        }
        t.nameSpace.mu.Unlock()
        if err != nil {
                return
        }
        return t.text.Execute(wr, data)
}
英文:

From the source code of template.go, the Execute function use a Lock, I'm a newbie, it looks is thread safe, but might not efficiency if put the template instance to a map and try to reuse it, if you need to serve lots of concurrent requests:

func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
        t.nameSpace.mu.Lock()
        if !t.escaped {
                if err = escapeTemplates(t, t.Name()); err != nil {
                        t.escaped = true
                }
        }
        t.nameSpace.mu.Unlock()
        if err != nil {
                return
        }
        return t.text.Execute(wr, data)
}

答案3

得分: 0

另一种方法是如果模板与处理程序具有一对一的关系,则使用闭包。好处是模板只执行一次,不需要全局变量,但缺点是模板只能在声明它的处理程序内部使用。

func templateHandler() http.HandlerFunc {

	// 模板只执行一次
	tmp := template.Must(template.ParseFiles("welcome.html"))

	// 通过闭包返回具有可用模板的处理程序
	return func(w http.ResponseWriter, r *http.Request) {
		// ...执行其他处理程序工作...
		// 根据数据执行模板
		tmp.Execute(w, myData)
	}
}

func main() {
	http.HandleFunc("/gopher", templateHandler())
	http.ListenAndServe(":8080", nil)
}
英文:

Another approach is to use a closure if the template has a 1-to-1 relationship with the handler. The benefit is the template is only executed once and does not require a global variable, but the downside is the template can only be used within the handler where it was declared.

func templateHandler() http.HandlerFunc {

	// template is executed once
	tmp := template.Must(template.ParseFiles("welcome.html"))

	// return our handler with the template available through the closure
	return func(w http.ResponseWriter, r *http.Request) {
		// ...perform other handler work ...
		// execute template against data
		tmp.Execute(w, myData)
	}
}

func main() {
	http.HandleFunc("/gopher", templateHandler())
	http.ListenAndServe(":8080", nil)
}

huangapple
  • 本文由 发表于 2013年3月12日 10:14:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/15352130.html
匿名

发表评论

匿名网友

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

确定