Skip to content

Commit 6502037

Browse files
committed
add codegen examples + wrap up efficient/inefficient fan-in-out examples
1 parent c908b4f commit 6502037

File tree

8 files changed

+166
-28
lines changed

8 files changed

+166
-28
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
.idea/
22
.DS_Store
3+
*_generated.go

patterns/codegen/main.go

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"log"
7+
"os"
8+
"text/template"
9+
"time"
10+
11+
"concurrency/patterns/codegen/templates"
12+
)
13+
14+
type data struct {
15+
Tpl string
16+
Pkg string
17+
Type string
18+
}
19+
20+
func main() {
21+
dataTpl := flag.String("tpl", "", "the template name")
22+
dataType := flag.String("type", "interface{}", "the built-in type for generator")
23+
dataPackage := flag.String("pkg", "main", "the package, the generated code belongs to")
24+
flag.Parse()
25+
d := data{
26+
Tpl: *dataTpl,
27+
Pkg: *dataPackage,
28+
Type: *dataType,
29+
}
30+
31+
var t string
32+
switch d.Tpl {
33+
case "fanin":
34+
t = templates.FanInTpl
35+
case "repeat":
36+
t = templates.RepeatTpl
37+
case "repeatfn":
38+
t = templates.RepeatFnTpl
39+
case "take":
40+
t = templates.TakeTpl
41+
default:
42+
log.Fatalf("could not find: %v", d.Tpl)
43+
}
44+
header := fmt.Sprintf(
45+
"// Code generated by go generate; DO NOT EDIT.\n"+
46+
"// This file was generated by the matrix at:\n// %s\n",
47+
time.Now(),
48+
)
49+
t = header + t + "\n"
50+
51+
tpl := template.Must(template.New(d.Tpl).Parse(t))
52+
file, err := os.Create(d.Tpl + "_generated.go")
53+
if err != nil {
54+
log.Fatalf("could not create file: %v", err)
55+
}
56+
57+
err = tpl.Execute(file, d)
58+
if err != nil {
59+
log.Fatalf("could not execute template: %v", err)
60+
}
61+
}

patterns/codegen/templates/fanin.go

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package templates
2+
3+
const FanInTpl = `package {{.Pkg}}
4+
5+
import "sync"
6+
7+
func FanIn(done chan struct{}, inputs ...<-chan {{.Type}}) <-chan {{.Type}} {
8+
out := make(chan {{.Type}})
9+
var wg sync.WaitGroup
10+
wg.Add(len(inputs))
11+
12+
for _, in := range inputs {
13+
go func(numbers <-chan {{.Type}}) {
14+
defer wg.Done()
15+
for n := range numbers {
16+
select {
17+
case <-done:
18+
return
19+
case out <- n:
20+
}
21+
}
22+
}(in)
23+
}
24+
go func() {
25+
wg.Wait()
26+
close(out)
27+
}()
28+
29+
return out
30+
}`

patterns/codegen/templates/repeat.go

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package templates
2+
3+
const RepeatTpl = `package {{.Pkg}}
4+
5+
func Repeat(done <-chan struct{}, values ...{{.Type}}) <-chan {{.Type}} {
6+
out := make(chan {{.Type}})
7+
go func() {
8+
defer close(out)
9+
for {
10+
for _, v := range values {
11+
select {
12+
case <-done:
13+
return
14+
case out <- v:
15+
}
16+
}
17+
}
18+
}()
19+
return out
20+
}`
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package templates
2+
3+
const RepeatFnTpl = `package {{.Pkg}}
4+
5+
func RepeatFn(done <-chan struct{}, fn func() {{.Type}}) <-chan {{.Type}} {
6+
out := make(chan {{.Type}})
7+
go func() {
8+
defer close(out)
9+
for {
10+
select {
11+
case <-done:
12+
return
13+
case out <- fn():
14+
}
15+
}
16+
}()
17+
return out
18+
}`

patterns/codegen/templates/take.go

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package templates
2+
3+
const TakeTpl = `package {{.Pkg}}
4+
5+
func Take(done <-chan struct{}, in <-chan {{.Type}}, num int) <-chan {{.Type}} {
6+
out := make(chan {{.Type}})
7+
go func() {
8+
defer close(out)
9+
for i := 0; i < num; i++ {
10+
select {
11+
case <-done:
12+
return
13+
case out <- <-in:
14+
}
15+
}
16+
}()
17+
return out
18+
}`

patterns/fan-in-out/efficient/main.go

+11-15
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,40 @@
1+
//go:generate go run ../../codegen/main.go -tpl=fanin -type=int
2+
//go:generate go run ../../codegen/main.go -tpl=repeatfn -type=int
3+
//go:generate go run ../../codegen/main.go -tpl=take -type=int
14
package main
25

36
import (
4-
"concurrency/patterns/fanin"
57
"fmt"
68
"math/rand"
79
"runtime"
810
"time"
9-
10-
"concurrency/patterns/generators"
11-
)
12-
13-
var (
14-
take = generators.Take
15-
toInt = generators.ToInt
16-
repeatFn = generators.RepeatFn
1711
)
1812

13+
// before running main.go, make sure to run:
14+
// go generate main.go
1915
func main() {
2016
done := make(chan struct{})
2117
defer close(done)
22-
random := func() interface{} {
18+
random := func() int {
2319
return rand.Intn(50000000)
2420
}
2521
start := time.Now()
26-
randIntStream := toInt(done, repeatFn(done, random))
22+
randIntStream := RepeatFn(done, random)
2723
numFinders := runtime.NumCPU()
2824
finders := make([]<-chan int, numFinders)
2925
for i := 0; i < numFinders; i++ {
30-
finders[i] = toInt(done, primeFinder(done, randIntStream))
26+
finders[i] = primeFinder(done, randIntStream)
3127
}
3228

3329
fmt.Println("primes:")
34-
for prime := range take(done, fanin.FanIn(done, finders...), 10) {
30+
for prime := range Take(done, FanIn(done, finders...), 10) {
3531
fmt.Println("prime:", prime)
3632
}
3733
fmt.Printf("search took: %v", time.Since(start))
3834
}
3935

40-
func primeFinder(done <-chan struct{}, intStream <-chan int) <-chan interface{} {
41-
primeStream := make(chan interface{})
36+
func primeFinder(done <-chan struct{}, intStream <-chan int) <-chan int {
37+
primeStream := make(chan int)
4238
go func() {
4339
defer close(primeStream)
4440
for integer := range intStream {

patterns/fan-in-out/inefficient/main.go

+7-13
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,31 @@
1+
//go:generate go run ../../codegen/main.go -tpl=repeatfn -type=int
2+
//go:generate go run ../../codegen/main.go -tpl=take -type=int
13
package main
24

35
import (
46
"fmt"
57
"math/rand"
68
"time"
7-
8-
"concurrency/patterns/generators"
9-
)
10-
11-
var (
12-
take = generators.Take
13-
toInt = generators.ToInt
14-
repeatFn = generators.RepeatFn
159
)
1610

1711
func main() {
1812
done := make(chan struct{})
1913
defer close(done)
20-
random := func() interface{} {
14+
random := func() int {
2115
return rand.Intn(50000000)
2216
}
2317
start := time.Now()
2418

25-
randIntStream := toInt(done, repeatFn(done, random))
19+
randIntStream := RepeatFn(done, random)
2620
fmt.Println("primes:")
27-
for prime := range take(done, primeFinder(done, randIntStream), 10) {
21+
for prime := range Take(done, primeFinder(done, randIntStream), 10) {
2822
fmt.Println("prime:", prime)
2923
}
3024
fmt.Printf("search took: %v", time.Since(start))
3125
}
3226

33-
func primeFinder(done <-chan struct{}, intStream <-chan int) <-chan interface{} {
34-
primeStream := make(chan interface{})
27+
func primeFinder(done <-chan struct{}, intStream <-chan int) <-chan int {
28+
primeStream := make(chan int)
3529
go func() {
3630
defer close(primeStream)
3731
for integer := range intStream {

0 commit comments

Comments
 (0)