package yetAnotherNewFunc
import ( "fmt" "reflect" "sync" "testing" ) type Foo struct{} func NewFoo() *Foo { return &Foo{} } func YieldFoo() Foo { return Foo{} } func SpawnFoo(F func(interface{}) error) chan Foo { chFoo := make(chan Foo) go func() { for { x := <-chFoo F(x) } }() return chFoo } func NSpawnFoo(N int, F func(interface{}) error) []chan Foo { NFoo := make([]chan Foo, 0, N) for i := 0; i < N; i++ { NFoo = append(NFoo, SpawnFoo(F)) } return NFoo } func IsFoo(x interface{}) (ret bool) { return reflect.TypeOf(Foo{}) == reflect.ValueOf(x).Type() } func ExampleFoo() { n := 5 var wg sync.WaitGroup wg.Add(n) f := func(x interface{}) error { fmt.Printf("%T => %v\n", x, IsFoo(x)); wg.Done(); return nil } NSF := NSpawnFoo(n, f) for _, ch := range NSF { ch <- YieldFoo() } wg.Wait() // Output: // yetAnotherNewFunc.Foo => true // yetAnotherNewFunc.Foo => true // yetAnotherNewFunc.Foo => true // yetAnotherNewFunc.Foo => true // yetAnotherNewFunc.Foo => true } func (f Foo) Bar() {} type FooBar interface { Bar() } func MustFooBar(x interface{}) FooBar { return x.(FooBar) } func TestMustFooBar(t *testing.T) { caseTable := []struct { Case interface{} Want bool }{ {Foo{}, true}, {struct{}{}, false}, } for _, tc := range caseTable { defer func() { if e := recover(); e != nil && tc.Want { t.Errorf("MustFooBar(%v) panic, %v", tc.Case, e) } }() _ = MustFooBar(tc.Case) } }
Hello, test!
Hello, this blog post from command line on\
fizzbuzz with 'knock group'
package main import ( "flag" "fmt" "io" "net/http" "strconv" "sync" ) var ( vol = flag.Int("v", 100, "volume") max = flag.Int("m", 10000, "send numbers") ) type msg struct { Q int A int I interface{} } type comm struct { Sch chan msg Rch chan msg } type reply struct { Comm chan *comm } var ( poolSub chan reply = make(chan reply) poolAdd chan *comm = make(chan *comm) ) var ( standbyPub chan reply = make(chan reply) standbyOk chan *comm = make(chan *comm) ) func save() { var ( pool []*comm = make([]*comm, 0, *vol) standby []*comm = make([]*comm, 0, *vol) ) for { select { case x := <-poolSub: last := len(pool) - 1 if last > 0 { x.Comm <- pool[last] pool = pool[:last] } else { x.Comm <- nil } case x := <-poolAdd: standby = append(standby, x) case y := <-standbyPub: last := len(standby) - 1 if last > 0 { y.Comm <- standby[last] standby = standby[:last] } else { y.Comm <- nil } case y := <-standbyOk: pool = append(pool, y) } } } func set() func(func(msg) msg) { var comms []comm for i := 0; i < *vol; i++ { comms = append(comms, comm{}) comms[i].Sch = make(chan msg) comms[i].Rch = make(chan msg) } return func(g func(x msg) msg) { for i := 0; i < *vol; i++ { i := i rch := comms[i].Sch sch := comms[i].Rch poolAdd <- &comms[i] go func() { for { x := <-rch sch <- g(x) poolAdd <- &comms[i] } }() } } } const ( FIZZBUZZ = iota FIZZ BUZZ NOTFIZZBUZZ ) func init() { flag.Parse() go save() f := set() g := func(m msg) msg { x := m.Q switch { case x%15 == 0: m.A = FIZZBUZZ case x%3 == 0: m.A = FIZZ case x%5 == 0: m.A = BUZZ default: m.A = NOTFIZZBUZZ } return m } f(g) } var ctrl chan struct{} = make(chan struct{}) func let() { close(ctrl) } func send(g func() msg) { for i := 0; i < *max; i++ { go func() { res := make(chan *comm) <-ctrl for { poolSub <- reply{res} c := <-res if c != nil { c.Sch <- g() break } } close(res) }() } } // done is for waiting all-received-timing var done chan struct{} = make(chan struct{}) func wait() { <-done } func recv(f func(chan msg) error) { var wg sync.WaitGroup wg.Add(*max) go func() { for { res := make(chan *comm) standbyPub <- reply{res} c := <-res if c != nil { go func() { f(c.Rch) wg.Done() }() standbyOk <- c } close(res) } }() wg.Wait() close(done) } // knockGroup has writer for answering against the knock, // and waitgroup of the knock. type knockGroup struct { W io.Writer WG *sync.WaitGroup } func main() { // "Knock-service" // GET http://localhost:8080/knock?k=n // then n'th fizzbuzz execute. f := func() func() msg { var n int knock := make(chan knockGroup) http.HandleFunc("/knock", func(w http.ResponseWriter, r *http.Request) { k := r.URL.Query().Get("k") var wg sync.WaitGroup if rep, err := strconv.Atoi(k); err == nil { wg.Add(rep) for ; rep > 0; rep-- { knock <- knockGroup{w, &wg} } } else { wg.Add(1) knock <- knockGroup{w, &wg} } wg.Wait() }) go http.ListenAndServe(":8080", nil) return func() msg { kG := <-knock n++ return msg{Q: n, I: kG} } } // send and g sends numbers to setted goroutines g := f() go send(g) // recv and h processes the results from setted goroutines h := func(ch chan msg) error { m := <-ch var ans string switch m.A { case FIZZBUZZ: ans = "fizzbuzz" case FIZZ: ans = "fizz" case BUZZ: ans = "buzz" case NOTFIZZBUZZ: ans = "-" } fmt.Fprintf(m.I.(knockGroup).W, "%v%v%v\n", m.Q, ":", ans) m.I.(knockGroup).WG.Done() return nil } go recv(h) let() // start wait() // wait }
fizzbuzz timer
package main import ( "context" "fmt" "time" ) const ( FIZZBUZZ = iota FIZZ BUZZ NOTFIZZBUZZ ) type result byte func (r result) String() string { if r&(1<<FIZZBUZZ) > 0 { return "fizzbuzz" } if r&(1<<FIZZ) > 0 { return "fizz" } if r&(1<<BUZZ) > 0 { return "buzz" } if r&(1<<NOTFIZZBUZZ) > 0 { return "notFizzbuzz" } return "out-of-fizzbuzz" } func (r *result) Add(n int) error { p := *r *r = p | 1<<uint(n) return nil } func recv(ctx context.Context, in <-chan int) (q int64, r result) { defer func() { q = ctx.Value("q").(int64) }() for { select { case x := <-in: switch x { case FIZZBUZZ: defer r.Add(x) return case FIZZ: defer r.Add(x) case BUZZ: defer r.Add(x) case NOTFIZZBUZZ: defer r.Add(x) return } case <-ctx.Done(): return } } return } func resPrint(q int64, r result) { fmt.Printf("%v %v %v\n", time.Unix(q/1000000000, q%1000000000).Format(time.RubyDate), q, r) } func launch(ctx context.Context, out chan<- int) { go do(ctx, 15, FIZZBUZZ, out) go do(ctx, 3, FIZZ, out) go do(ctx, 5, BUZZ, out) go dont(ctx, NOTFIZZBUZZ, out) } func do(ctx context.Context, d int64, a int, out chan<- int) error { q := ctx.Value("q").(int64) if q != 0 && q%d == 0 { select { case out <- a: case <-ctx.Done(): return ctx.Err() } } return nil } func dont(ctx context.Context, a int, out chan<- int) error { q := ctx.Value("q").(int64) if q%3 != 0 && q%5 != 0 { select { case out <- a: case <-ctx.Done(): return ctx.Err() } } return nil } func main() { for { now := time.Now().UnixNano() ctx := context.WithValue(context.Background(), "q", now) go func() { ctx, cancel := context.WithTimeout(ctx, 500*time.Millisecond) defer cancel() ch := make(chan int) go launch(ctx, ch) resPrint(recv(ctx, ch)) }() } }
■
import ( "context" "flag" "fmt" "time" ) const ( FIZZBUZZ = iota FIZZ BUZZ NOTFIZZBUZZ ) type msg struct { Q int A int } type ring struct { next *ring f ringer } type ringer interface { Do(ctx context.Context, out chan<- msg) error } type fizzbuzz struct{} func (fizzbuzz) Do(ctx context.Context, out chan<- msg) error { return do(ctx, 15, FIZZBUZZ, out) } type fizz struct{} func (f fizz) Do(ctx context.Context, out chan<- msg) error { return do(ctx, 3, FIZZ, out) } type buzz struct{} func (b buzz) Do(ctx context.Context, out chan<- msg) error { return do(ctx, 5, BUZZ, out) } func do(ctx context.Context, d, a int, out chan<- msg) error { n := ctx.Value("n") if n == nil { return fmt.Errorf("fizzbuzz-request-value is empty") } if n.(int)%d == 0 { select { case out <- msg{Q: n.(int), A: a}: case <-ctx.Done(): } } return nil } type notFizzbuzz struct{} func (nfb notFizzbuzz) Do(ctx context.Context, out chan<- msg) error { n := ctx.Value("n") if n == nil { return fmt.Errorf("fizzbuzz-request-value is empty") } if n.(int)%3 != 0 && n.(int)%5 != 0 { select { case out <- msg{Q: n.(int), A: NOTFIZZBUZZ}: case <-ctx.Done(): } } return nil } func set() (*ring, int) { rings := []ring{ {nil, fizzbuzz{}}, {nil, fizz{}}, {nil, buzz{}}, {nil, notFizzbuzz{}}, } for i := 0; i < len(rings); i++ { j := i + 1 if j >= len(rings) { j = 0 } rings[i].next = &rings[j] } return &rings[0], cap(rings) } var req chan int = make(chan int) func circle(cur *ring, m int) { ctx := context.Background() for { i := <-req ctx := context.WithValue(ctx, "n", i) go func() { ctx, cancel := context.WithTimeout(ctx, 500*time.Millisecond) defer cancel() res := make(chan msg) go circleline(ctx, cur, m, res) fmt.Println(recv(ctx, res)) }() } } func circleline(ctx context.Context, cur *ring, m int, out chan<- msg) { for ; m > 0; m-- { go cur.f.Do(ctx, out) cur = cur.next } } func recv(ctx context.Context, res <-chan msg) (buf struct { Q int A [4]string T string }) { for { select { case x := <-res: defer func() { buf.Q = x.Q }() switch x.A { case FIZZBUZZ: defer func() { buf.A[FIZZBUZZ] = "fizzbuzz" }() return case FIZZ: defer func() { buf.A[FIZZ] = "fizz" }() case BUZZ: defer func() { buf.A[BUZZ] = "buzz" }() case NOTFIZZBUZZ: defer func() { buf.A[NOTFIZZBUZZ] = "-" }() return } case <-ctx.Done(): defer func() { buf.T = time.Now().Format(time.StampNano) }() return } } } var max = flag.Int("m", 100000, "send numbers") func main() { flag.Parse() term, n := set() go circle(term, n) for i := 0; i < *max; i++ { req <- i } time.Sleep(time.Second) }