为啥使用goroutine后计算任务的总时间基本一样
Posted
技术标签:
【中文标题】为啥使用goroutine后计算任务的总时间基本一样【英文标题】:Why the total time of computing tasks after using goroutine is basically the same为什么使用goroutine后计算任务的总时间基本一样 【发布时间】:2022-01-21 23:26:16 【问题描述】:不使用 goroutine 时,500 * 100000000 次加一
// 1m12.2857724s
start := time.Now()
for i := 0; i < 500; i++
res := 0
for j := 0; j < 100000000; j++
res++
duration := time.Since(start)
fmt.Println(duration)
使用 goroutine 时,10 个 goroutine 执行 50 * 100000000 次加一
// 1m12.0174541s
start := time.Now()
ch := make(chan bool)
for i := 0; i < 10; i++
go func(ch chan bool)
for i := 0; i < 50; i++
res := 0
for j := 0; j < 100000000; j++
res++
ch <- true
(ch)
<- ch
duration := time.Since(start)
fmt.Println(duration)
为什么使用 goroutine 不节省时间
【问题讨论】:
ch
的目的是什么?
【参考方案1】:
ch
频道没有缓冲。你启动一个 goroutine 并在最后在通道上发送一个值,然后在启动另一个 goroutine 之前,你会从它接收。这是一个阻塞操作。在一个完成之前,你不会启动一个新的 goroutine。与第一个解决方案相比,您一无所获。
一个“解决方案”是让通道缓冲,并且只有在所有 goroutine 启动后才开始接收:
ch := make(chan bool, 10)
for i := 0; i < 10; i++
go func(ch chan bool)
for i := 0; i < 50; i++
res := 0
for j := 0; j < 100000000; j++
res++
ch <- true
(ch)
for i := 0; i < 10; i++
<-ch
这将在我的计算机(4 个 CPU 内核)上带来几乎 4 倍的加速。
等待所有 goroutine 的更好、更惯用的方法是使用 sync.WaitGroup
:
var wg sync.WaitGroup
for i := 0; i < 10; i++
wg.Add(1)
go func()
defer wg.Done()
for i := 0; i < 50; i++
res := 0
for j := 0; j < 100000000; j++
res++
()
wg.Wait()
另外请注意,使用多个 goroutine 仅在它们所做的任务“重要”时才值得,请参阅:
Matrix multiplication with goroutine drops performance
Vectorise a function taking advantage of concurrency
【讨论】:
【参考方案2】:您可以有效地启动 10 个 goroutine,并在它们完成工作后从每个 goroutine 中以简单的方式接收。
检查你的代码的 CPU 使用率,以及这个
func add(ch chan int)
r := 0
for i := 0; i < 50; i++
for j := 0; j < 100000000; j++
r++
ch <- r
func main()
start := time.Now()
ch := make(chan int)
res := 0
for i := 0; i < 10; i++
go add(ch)
for i := 0; i < 10; i++
res += <-ch
duration := time.Since(start)
fmt.Println(duration, res)
输出
3.747405005s 50000000000
这将成功启动 10 个 goroutine,每个 goroutine 执行其工作并在完成后将结果返回到通道中。
【讨论】:
以上是关于为啥使用goroutine后计算任务的总时间基本一样的主要内容,如果未能解决你的问题,请参考以下文章