英文:
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)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论