英文:
Why the total time of computing tasks after using goroutine is basically the same
问题
当不使用goroutine时,执行500 * 100000000次加一的操作需要1m12.2857724秒。代码如下:
// 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.0174541秒。代码如下:
// 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不会节省时间呢?
英文:
When not using goroutine,500 * 100000000 times plus one
// 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)
When using goroutine, 10 goroutines execute 50 * 100000000 times plus one
// 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)
Why use goroutine does not save time
答案1
得分: 3
ch
通道是无缓冲的。你在最后启动一个goroutine并在通道上发送一个值,然后在启动另一个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执行的任务是"重要的"时,使用多个goroutine才值得,参见:
英文:
The ch
channel is unbuffered. You launch a goroutine and send a value on the channel at the end, and right after that, before launching another goroutine you receive from it. This is a blocking operation. You won't start a new goroutine until one is finished. You gain nothing compared to the first solution.
One "solution" is to make the channel buffered, and only start receiving from it once all goroutines have been launched:
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
}
This will result in almost 4x speedup on my computer (4 CPU cores).
A better, more idiomatic way to wait for all goroutines is to use 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()
Also note that using multiple goroutines is only worth it if the task they do is "significant", see:
答案2
得分: 0
你可以以一种简单的方式有效地启动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执行它们的工作,并在完成后通过通道返回结果。
英文:
You could effectively launch the 10 goroutines, and receive from each after they complete their work, in a simple way.
Check the CPU usage of your code, and this one
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)
}
Output
> 3.747405005s 50000000000
That will successfully launch the 10 goroutines, each of them perform their work and return the results down the channel once they're done.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论