Skip to content

Commit

Permalink
template: warn about interleaved nature of writes
Browse files Browse the repository at this point in the history
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 <r@golang.org>
  • Loading branch information
Dieterbe authored and robpike committed May 5, 2017
1 parent 27a10f7 commit 1acff5f
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 5 deletions.
6 changes: 4 additions & 2 deletions src/html/template/template.go
Expand Up @@ -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
Expand All @@ -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 {
Expand Down
3 changes: 2 additions & 1 deletion src/text/template/doc.go
Expand Up @@ -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".
Expand Down
6 changes: 4 additions & 2 deletions src/text/template/exec.go
Expand Up @@ -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 {
Expand All @@ -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.
Expand Down

0 comments on commit 1acff5f

Please sign in to comment.