我刚刚在朋友的推荐下开始学习go。到目前为止,我很喜欢它,但是我写了(我想会是)轻量级并发功能的完美例子,并且得到了令人惊讶的结果……所以我怀疑我做错了,或者误解了goroutine是多么昂贵。我希望这里的一些地鼠能提供见识。
我在Go中使用goroutine和简单的同步执行编写了Chudnovsky的算法。我假设,每次计算都独立于其他计算,因此并发运行至少要快一点。
注意 :我正在第5代i7上运行此程序,因此,如果按照我的要求,将goroutines多路复用到线程上,则应同时进行并发 和 并行处理。
package main import ( "fmt" "math" "strconv" "time" ) func main() { var input string var sum float64 var pi float64 c := make(chan float64) fmt.Print("How many iterations? ") fmt.Scanln(&input) max,err := strconv.Atoi(input) if err != nil { panic("You did not enter a valid integer") } start := time.Now() //start timing execution of concurrent routine for i := 0; i < max; i++ { go chudnovskyConcurrent(i,c) } for i := 0; i < max; i++ { sum += <-c } end := time.Now() //end of concurrent routine fmt.Println("Duration of concurrent calculation: ",end.Sub(start)) pi = 1/(12*sum) fmt.Println(pi) start = time.Now() //start timing execution of syncronous routine sum = 0 for i := 0; i < max; i++ { sum += chudnovskySync(i) } end = time.Now() //end of syncronous routine fmt.Println("Duration of synchronous calculation: ",end.Sub(start)) pi = 1/(12*sum) fmt.Println(pi) } func chudnovskyConcurrent(i int, c chan<- float64) { var numerator float64 var denominator float64 ifloat := float64(i) iun := uint64(i) numerator = math.Pow(-1, ifloat) * float64(factorial(6*iun)) * (545140134*ifloat+13591409) denominator = float64(factorial(3*iun)) * math.Pow(float64(factorial(iun)),3) * math.Pow(math.Pow(640320,3),ifloat+0.5) c <- numerator/denominator } func chudnovskySync(i int) (r float64) { var numerator float64 var denominator float64 ifloat := float64(i) iun := uint64(i) numerator = math.Pow(-1, ifloat) * float64(factorial(6*iun)) * (545140134*ifloat+13591409) denominator = float64(factorial(3*iun)) * math.Pow(float64(factorial(iun)),3) * math.Pow(math.Pow(640320,3),ifloat+0.5) r = numerator/denominator return } func factorial(n uint64) (res uint64) { if ( n > 0 ) { res = n * factorial(n-1) return res } return 1 }
这是我的结果:
How many iterations? 20 Duration of concurrent calculation: 573.944µs 3.1415926535897936 Duration of synchronous calculation: 63.056µs 3.1415926535897936
您正在进行的计算太简单了,无法在单独的goroutine中进行每个计算。与实际计算相比,您在运行时中浪费的时间更多(创建goroutine,复用,调度等)。例如,您尝试做的事情更适合于GPU,因为您拥有大量并行执行单元,这些单元可以立即进行一次简单的计算。但是您将需要其他语言和API来做到这一点。
您可以做的是为每个执行硬件线程创建执行软件线程。您想将max变量拆分为大块并并行执行。这是一个非常简单的例子,仅用于说明这个想法:
max
package main import ( "fmt" "math" "strconv" "time" "runtime" ) func main() { var input string var sum float64 var pi float64 c := make(chan float64, runtime.GOMAXPROCS(-1)) fmt.Print("How many iterations? ") fmt.Scanln(&input) max,err := strconv.Atoi(input) if err != nil { panic("You did not enter a valid integer") } start := time.Now() //start timing execution of concurrent routine for i := 0; i < runtime.GOMAXPROCS(-1); i++ { go func(i int){ var sum float64 for j := 0; j < max/runtime.GOMAXPROCS(-1); j++ { sum += chudnovskySync(j + i*max/runtime.GOMAXPROCS(-1)) } c <- sum }(i) } for i := 0; i < runtime.GOMAXPROCS(-1); i++ { sum += <-c } end := time.Now() //end of concurrent routine fmt.Println("Duration of concurrent calculation: ",end.Sub(start)) pi = 1/(12*sum) fmt.Println(pi) start = time.Now() //start timing execution of syncronous routine sum = 0 for i := 0; i < max; i++ { sum += chudnovskySync(i) } end = time.Now() //end of syncronous routine fmt.Println("Duration of synchronous calculation: ",end.Sub(start)) pi = 1/(12*sum) fmt.Println(pi) } func chudnovskySync(i int) (r float64) { var numerator float64 var denominator float64 ifloat := float64(i) iun := uint64(i) numerator = math.Pow(-1, ifloat) * float64(factorial(6*iun)) * (545140134*ifloat+13591409) denominator = float64(factorial(3*iun)) * math.Pow(float64(factorial(iun)),3) * math.Pow(math.Pow(640320,3),ifloat+0.5) r = numerator/denominator return } func factorial(n uint64) (res uint64) { if ( n > 0 ) { res = n * factorial(n-1) return res } return 1 }
这是结果
$ go version go version go1.5.2 windows/amd64 $ go run main.go GOMAXPROCS = 4 How many iterations? 10000 Duration of concurrent calculation: 932.8916ms NaN Duration of synchronous calculation: 2.0639744s NaN