package main import ( "bytes" "fmt" "log" "runtime" "strconv" "time" ) func main() { runtime.GOMAXPROCS(runtime.NumCPU()) beginTime := time.Now() origin := make(chan int) wait := make(chan struct{}) process(origin, wait) for num := 2; num < 10000; num++ { origin <- num } close(origin) <-wait fmt.Println("All done. Time: " + time.Now().Sub(beginTime).String()) } func process(seq chan int, wait chan struct{}) { go func() { prime, ok := <-seq if !ok { close(wait) return } notifyGotPrime(prime) out := make(chan int) process(out, wait) for num := range seq { if num%prime != 0 { out <- num } } close(out) }() } func notifyGotPrime(prime int) { fmt.Printf("[%d]: %d\n", getGoRoutineId(), prime) } func getGoRoutineId() uint64 { b := make([]byte, 32) b = b[:runtime.Stack(b, false)] b = bytes.TrimPrefix(b, []byte("goroutine ")) b = b[:bytes.IndexByte(b, ' ')] id, err := strconv.ParseUint(string(b), 10, 64) if err != nil { log.Panicf("Cannot parse goroutine id from %v: %v", b, err) } return id }