From 1acff5fe61013d4f5b1ed6602654abbbe73b1599 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Fri, 10 Feb 2017 11:54:58 +0100 Subject: [PATCH] template: warn about interleaved nature of writes Execute incurs separate writes for each "step", e.g. each variable that needs to be printed, and the final newline. While it is correct to state that templates can be executed concurrently, there is a more subtle nuance that is easily missed: when writing to the same writer, the writes from concurrent execute calls can be interleaved, leading to unexpected output. Change-Id: I0abbd7960d8a8d15e109a8a3eeff3b43b852bbbf Reviewed-on: https://go-review.googlesource.com/37444 Reviewed-by: Rob Pike --- src/html/template/template.go | 6 ++++-- src/text/template/doc.go | 3 ++- src/text/template/exec.go | 6 ++++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/html/template/template.go b/src/html/template/template.go index e1f179abc2..246ef04dbe 100644 --- a/src/html/template/template.go +++ b/src/html/template/template.go @@ -112,7 +112,8 @@ func (t *Template) escape() error { // If an error occurs executing the template or writing its output, // execution stops, but partial results may already have been written to // the output writer. -// A template may be executed safely in parallel. +// A template may be executed safely in parallel, although if parallel +// executions share a Writer the output may be interleaved. func (t *Template) Execute(wr io.Writer, data interface{}) error { if err := t.escape(); err != nil { return err @@ -125,7 +126,8 @@ func (t *Template) Execute(wr io.Writer, data interface{}) error { // If an error occurs executing the template or writing its output, // execution stops, but partial results may already have been written to // the output writer. -// A template may be executed safely in parallel. +// A template may be executed safely in parallel, although if parallel +// executions share a Writer the output may be interleaved. func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error { tmpl, err := t.lookupAndEscapeTemplate(name) if err != nil { diff --git a/src/text/template/doc.go b/src/text/template/doc.go index fe59e3f74e..b35fe39ecc 100644 --- a/src/text/template/doc.go +++ b/src/text/template/doc.go @@ -20,7 +20,8 @@ The input text for a template is UTF-8-encoded text in any format. "{{" and "}}"; all text outside actions is copied to the output unchanged. Except for raw strings, actions may not span newlines, although comments can. -Once parsed, a template may be executed safely in parallel. +Once parsed, a template may be executed safely in parallel, although if parallel +executions share a Writer the output may be interleaved. Here is a trivial example that prints "17 items are made of wool". diff --git a/src/text/template/exec.go b/src/text/template/exec.go index 0e517a6ec3..e54a579afd 100644 --- a/src/text/template/exec.go +++ b/src/text/template/exec.go @@ -153,7 +153,8 @@ func errRecover(errp *error) { // If an error occurs executing the template or writing its output, // execution stops, but partial results may already have been written to // the output writer. -// A template may be executed safely in parallel. +// A template may be executed safely in parallel, although if parallel +// executions share a Writer the output may be interleaved. func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error { var tmpl *Template if t.common != nil { @@ -170,7 +171,8 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) // If an error occurs executing the template or writing its output, // execution stops, but partial results may already have been written to // the output writer. -// A template may be executed safely in parallel. +// A template may be executed safely in parallel, although if parallel +// executions share a Writer the output may be interleaved. // // If data is a reflect.Value, the template applies to the concrete // value that the reflect.Value holds, as in fmt.Print. -- 2.48.1