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
CodePudding user response:
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.
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:
Matrix multiplication with goroutine drops performance
Vectorise a function taking advantage of concurrency
CodePudding user response:
In addition to what @icza said, 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.