package main import "fmt" import "time" import . "math/big" func source(dst chan *Int) { for k := NewInt(1); k.Cmp(NewInt(100000)) == -1; k.Add(k, NewInt(1)) { x := NewInt(0) x.Add(k, NewInt(1)) x.Mul(x, k) x.Div(x, NewInt(2)) dst <- x } close(dst) } func makePairs(src chan *Int, dst chan [2]*Int) { var v1, v2 *Int var ok1, ok2 bool for { v1, ok1 = <-src v2, ok2 = <-src if !(ok1 && ok2) { break } dst <- [2]*Int{v1, v2} } close(dst) } func split(src chan [2]*Int, dst1 chan [2]*Int, dst2 chan [2]*Int) { for chunk := range src { dst1 <- chunk dst2 <- chunk } close(dst1) close(dst2) } func multiply(src chan [2]*Int, dst chan *Int) { for chunk := range src { x := NewInt(0) x.Mul(chunk[0], chunk[1]) dst <- x } close(dst) } func gcd(src chan [2]*Int, dst chan *Int) { var helper func(*Int, *Int) helper = func(x *Int, y *Int) { if x.Cmp(y) == -1 { helper(y, x) } else if y.Cmp(NewInt(0)) == 0 { dst <- x } else { z := NewInt(0) z.Mod(x, y) helper(y, z) } } for chunk := range src { helper(chunk[0], chunk[1]) } close(dst) } func combine(src1 chan *Int, src2 chan *Int, dst chan [2]*Int) { var v1, v2 *Int var ok1, ok2 bool for { v1, ok1 = <-src1 v2, ok2 = <-src2 if !(ok1 && ok2) { break } dst <- [2]*Int{v1, v2} } close(dst) } func divide(src chan [2]*Int, dst chan *Int) { for chunk := range src { x := NewInt(0) x.Div(chunk[0], chunk[1]) dst <- x } close(dst) } func getDigits(src chan *Int, dst chan *Int) { var helper func(*Int) helper = func(x *Int) { if x.Cmp(NewInt(0)) != 0 { y := NewInt(0) z := NewInt(0) y.Div(x, NewInt(10)) z.Mod(x, NewInt(10)) helper(y) dst <- z } } for chunk := range src { helper(chunk) } close(dst) } func sink(src chan *Int) { for _ = range src { } } func pipeline() { // Channels are unbuffered for a fair comparison with generators c1 := make(chan *Int) c2 := make(chan [2]*Int) c3 := make(chan [2]*Int) c4 := make(chan [2]*Int) c5 := make(chan *Int) c6 := make(chan *Int) c7 := make(chan [2]*Int) c8 := make(chan *Int) c9 := make(chan *Int) go source(c1) go makePairs(c1, c2) go split(c2, c3, c4) go multiply(c3, c5) go gcd(c4, c6) go combine(c5, c6, c7) go divide(c7, c8) go getDigits(c8, c9) sink(c9) } func main() { timer := time.Now() for i := 0; i < 100; i++ { pipeline() } fmt.Println(time.Now().Sub(timer)) }