7

为了处理 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)

4

3 回答 3

13

模板本身实际上可以充当模板的映射。这就是我所做的:

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

var t = template.New("master")

我实际上并没有使用“主”模板,除了作为其他模板的容器。

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

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

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

t.ExecuteTemplate(w, "user.html", data)
于 2013-03-12T03:18:30.803 回答
0

从template.go的源码来看,Execute函数使用了Lock,我是新手,看起来是线程安全的,但是如果需要的话,如果把模板实例放到一个map中尝试重用它可能效率不高服务大量并发请求:

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)
}
于 2013-03-12T03:04:52.250 回答
0

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

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

于 2021-08-11T12:14:58.350 回答