Home > front end >  Why the total time of computing tasks after using goroutine is basically the same
Why the total time of computing tasks after using goroutine is basically the same

Time:12-20

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.

  • Related