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.

Reply via email to