The best thing I can think of is to modify text/template to add futures 
support, and then do multi-pass rendering. The place to add this looks 
relatively simple, however the implementation looks complicated (and I just 
wrote my first program in go a couple weeks ago...)

The problem that I see with the solution below is that text/template 
execution tries to instantiate the values of each function serially and 
essentially waits for completion on each, serially. I've spent the last 
couple hours examining the text/template implementation.
--
Michael

On Wednesday, May 31, 2017 at 8:59:20 AM UTC-5, Egon wrote:
>
> 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