【发布时间】:2018-09-30 22:40:03
【问题描述】:
现在我通过观看 this great course 开始学习 Go 语言。需要明确的是,多年来我只写 PHP,并发/并行对我来说是新的,所以我对此有点困惑。
在本课程中,有一个任务是创建一个计算 100 次计算的阶乘程序。我更进一步,为了比较性能,我将其更改为 10000,出于某种原因,顺序程序的工作方式与并发程序相同甚至更快。
这里我将提供 3 个解决方案:我的、老师的和顺序的
我的解决方案:
package main
import (
"fmt"
)
func gen(steps int) <-chan int{
out := make(chan int)
go func() {
for j:= 0; j <steps; j++ {
out <- j
}
close(out)
}()
return out
}
func factorial(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- fact(n)
}
close(out)
}()
return out
}
func fact(n int) int {
total := 1
for i := n;i>0;i-- {
total *=i
}
return total
}
func main() {
steps := 10000
for i := 0; i < steps; i++ {
for n:= range factorial(gen(10)) {
fmt.Println(n)
}
}
}
执行时间:
- 真正的 0m6,356s
- 用户 0m3,885s
- sys 0m0,870s
老师解决方案: 主包
import (
"fmt"
)
func gen(steps int) <-chan int{
out := make(chan int)
go func() {
for i := 0; i < steps; i++ {
for j:= 0; j <10; j++ {
out <- j
}
}
close(out)
}()
return out
}
func factorial(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- fact(n)
}
close(out)
}()
return out
}
func fact(n int) int {
total := 1
for i := n;i>0;i-- {
total *=i
}
return total
}
func main() {
steps := 10000
for n:= range factorial(gen(steps)) {
fmt.Println(n)
}
}
执行时间:
- 真正的 0m2,836s
- 用户 0m1,388s
- sys 0m0,492s
顺序:
package main
import (
"fmt"
)
func fact(n int) int {
total := 1
for i := n;i>0;i-- {
total *=i
}
return total
}
func main() {
steps := 10000
for i := 0; i < steps; i++ {
for j:= 0; j <10; j++ {
fmt.Println(fact(j))
}
}
}
执行时间:
- 真正的 0m2,513s
- 用户 0m1,113s
- sys 0m0,387s
因此,您可以看到顺序解决方案最快,教师解决方案排在第二位,我的解决方案排在第三位。
第一个问题:为什么顺序解决方案最快?
其次,为什么我的解决方案这么慢?如果我在我的解决方案中理解正确,我将在 gen 中创建 10000 个 goroutine,在 factorial 和教师解决方案中创建 10000 个 goroutine,他在 gen 中仅创建 1 个 goroutine,在 factorial 中创建 1 个。我这么慢是因为我创建了太多不需要的 goroutine?
【问题讨论】:
标签: go concurrency parallel-processing factorial goroutine