Here's a proof-of-concept of a somewhat general mechanism for making template functions concurrent. It involves some fun reflection code (first time I've used FuncOf, MakeFunc, StructOf and MapOf for real).
https://play.golang.org/p/7qXx5pCh9N On 1 June 2017 at 07:02, Michael Brown <michael.e.br...@gmail.com> wrote: > Great! If I had checked this thread when you posted this I (probably) could > have saved myself 3 hours of work. > > I got it working with a two-pass scheme using text/template and some > channels. > > Here is what I came up with: > > package main > > > import ( > > "text/template" > > "bytes" > > "context" > > "fmt" > > "github.com/google/uuid" > > "time" > > ) > > > type resultpair struct { > > key string > > value string > > } > > > > func getFuncMap(ctx context.Context, resultsQueue chan resultpair) (*int, > template.FuncMap) { > > totalJobs := 0 > > var funcMap = template.FuncMap{ > > "sleep": func() string { > > totalJobs = totalJobs + 1 > > token := uuid.New() > > go func() { > > time.Sleep(1 * time.Second) > > resultsQueue <- resultpair{token.String(), "REAL_VALUE!"} > > }() > > return "{{ getOutput \"" + token.String() + "\" }}" > > }, > > } > > > return &totalJobs, funcMap > > } > > > func getFuncMapNested(ctx context.Context, output map[string]string) > template.FuncMap { > > var funcMapNested = template.FuncMap{ > > "getOutput": func(input string) string { return output[input] }, > > } > > return funcMapNested > > } > > > func main() { > > initial := "{{sleep}} {{sleep}} {{sleep}}" > > > resultsQueue := make(chan resultpair) > > outputQueue := make(chan map[string]string) > > // totalJobs is decieving: only ever accessed by one thread at a time, > so shouldn't need locking (I think) > > totalJobs, funcMap := getFuncMap(context.TODO(), resultsQueue) > > > fmt.Printf("About to execute first template: %s\n", initial) > > fmt.Printf("TOTAL JOBS: %d\n", *totalJobs) > > tmpl, _ := template.New("test").Funcs(funcMap).Parse(initial) > > var buf bytes.Buffer > > tmpl.Execute(&buf, nil) > > fmt.Printf("Got translated template: %s\n", buf.String()) > > fmt.Printf("TOTAL JOBS: %d\n", *totalJobs) > > > go func(totalJobs *int) { > > var results map[string]string > > results = make(map[string]string) > > > for i := 0; i < *totalJobs; i++ { > > res := <-resultsQueue > > results[res.key] = res.value > > } > > outputQueue <- results > > close(outputQueue) > > }(totalJobs) > > > output := <-outputQueue > > close(resultsQueue) > > fmt.Printf("Output of the goroutine: %s\n", output) > > > funcMapNested := getFuncMapNested(context.TODO(), output) > > tmpl2, _ := > template.New("nested").Funcs(funcMapNested).Parse(buf.String()) > > var buf2 bytes.Buffer > > tmpl2.Execute(&buf2, nil) > > > fmt.Printf("results: %s\n", buf2.String()) > > } > > > OUTPUT: > > > $ time go run ./commands/try.go > > About to execute first template: {{sleep}} {{sleep}} {{sleep}} > > TOTAL JOBS: 0 > > Got translated template: {{ getOutput "bc7dcfa0-89d9-45e9-bd40-eb2db6f51db0" > }} {{ getOutput "f2539f15-378b-408d-8c6e-d3822e985a6b" }} {{ getOutput > "56c9d239-d08d-43e8-80de-dd97ef157b6a" }} > > TOTAL JOBS: 3 > > Output of the goroutine: > map[bc7dcfa0-89d9-45e9-bd40-eb2db6f51db0:REAL_VALUE! > f2539f15-378b-408d-8c6e-d3822e985a6b:REAL_VALUE! > 56c9d239-d08d-43e8-80de-dd97ef157b6a:REAL_VALUE!] > > results: REAL_VALUE! REAL_VALUE! REAL_VALUE! > > > real 0m1.319s > > user 0m0.278s > > sys 0m0.098s > > > On Wednesday, May 31, 2017 at 9:09:51 PM UTC-5, robfig wrote: >> >> We do this exact thing except using closure templates >> https://blog.gopheracademy.com/advent-2014/soy-programmable-templates/ > > -- > 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. -- 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.