The best idea I can think of (without digging and modifying text/template) 
is to use special tokens and replace them afterwards...
Of course this approach has limitations in what it can do.

*// note: code untested and incomplete*

type Token string
type Queries struct {
    pending sync.WaitGroup
    mu sync.Mutex
    responses map[Token]string
}

func (q *Queries) createToken() Token {
    return unique token
}

func (q *Queries) Do(fn func() string) Token {
    token := q.createToken()
    q.pending.Add(1)
    go func(){
        defer q.pending.Done()
        result := fn()
        q.mu.Lock()
        q.responses[token] = result
        q.mu.Unlock()
    }()
    return token
}

func (q *Queries) Wait(){ q.pending.Wait() }
func (q *Queries) Patch(data []byte) []byte {
    // replace tokens with responess
}

func main() {

   q := NewQueries()

    var funcMap = template.FuncMap {

        "sleep": func() Token { return q.Do(func() string { time.Sleep(1 * 
time.Second); return "slept" }) },

    }
    tmpl, _ := template.New("test").Funcs(funcMap).Parse("{{sleep}} 
{{sleep}} {{sleep}}")
    var buf bytes.Buffer

    tmpl.Execute(&buf, nil)

    q.Wait()

    os.Stdout.Write(q.Patch(buf.Bytes))

}

The other approach would be to do multiple passes:

1. execute template
2. collect funcs that haven't been run yet
2.1. no funcs left --> output
3. execute these funcs, cache the func values
4. goto step 1 using the cache

On Wednesday, 31 May 2017 16:26:15 UTC+3, Michael Brown wrote:
>
> I am designing a system that will heavily use text/template processing and 
> I've run into one issue that is going to be a show stopper for me if I 
> can't figure out a way around it.
>
> Execute() on a template will run all of the functions in the template 
> serially. 
>
> For example, when you run the code below, you can see it output "slept" 
> once every second until it completes after 3 seconds. In this example, the 
> sleep is simulating an RPC call to another process that may take some 
> considerable time (few tenths of a second), but there will be a large 
> number of these calls that could all theoretically run in parallel (ie. 
> there are no data dependencies between them). I'd really like to know a way 
> that I could have the templating engine run all of the functions at once 
> and collect the output, ie. in the example below, the entire program should 
> run in 1 second.
>
> package main
>
>
> import (
>
>     "text/template"
>
>     "os"
>
>     "time"
>
> )
>
>
> var funcMap = template.FuncMap {
>
>     "sleep": func() string { time.Sleep(1 * time.Second); return "slept" },
>
> }
>
>
> func main() {
>
>     tmpl, _ := template.New("test").Funcs(funcMap).Parse("{{sleep}} 
> {{sleep}} {{sleep}}")
>
>     tmpl.Execute(os.Stdout, nil)
>
> }
>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to