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)
}