The use of sync.WaitGroup in collaboration

Scenarios used:

When several goroutine s are running at the same time, you need to wait for these processes to complete before doing other operations

Steps to use:

  1. Define an object
    2. Use the Add method of sync.WaitGroup to Add a count to the queue 3. Use the Done method of sync.WaitGroup to notify that a collaboration has completed 4. Use the Wait method of sync.WaitGroup to Wait for the completion of the cooperation process

Examples:

package main
import (
    "sync"
    "net/http"
    "io/ioutil"
    "fmt"
)
func download(i int,wg *sync.WaitGroup, url string) (err error){
    res, err := http.Get(url)
    if err != nil || res.StatusCode != 200 {
        fmt.Println("Down load erro")
        return err
    }
    data, err := ioutil.ReadAll(res.Body)
    if err != nil {
        fmt.Println("read failed")
        return err
    }
    ioutil.WriteFile(fmt.Sprintf("picture%d.data", i), data, 0644)

    wg.Done()
    return nil
}
func main() {
    var wg sync.WaitGroup
    for i := 0; i<200; i++ {
        wg.Add(1)
        go download(i,&wg,"http://www.pptok.com/wp-content/uploads/2012/08/xunguang-9.jpg")
    }
    wg.Wait()
}

What should be paid attention to when using:

The instance of sync.WaiteGroup used in the code of the collaboration must be a pointer, and the value cannot be passed. If the value is passed, an error will be reported because the reference number is negative. For example, change the above code to the following:

package main
import (
    "sync"
    "net/http"
    "io/ioutil"
    "fmt"
)
func download(i int,wg sync.WaitGroup, url string) (err error){
    fmt.Println("start download")
    res, err := http.Get(url)
    if err != nil || res.StatusCode != 200 {
        fmt.Println("Down load erro")
        return err
    }
    data, err := ioutil.ReadAll(res.Body)
    if err != nil {
        fmt.Println("read failed")
        return err
    }
    ioutil.WriteFile(fmt.Sprintf("picture%d.data", i), data, 0644)
    fmt.Println("finish download")
    wg.Done()
    
    return nil
}
func main() {
    var wg sync.WaitGroup
    for i := 0; i<200; i++ {
        wg.Add(1)
        go download(i,wg,"http://www.pptok.com/wp-content/uploads/2012/08/xunguang-9.jpg")
    }

    fmt.Println("finish!!!")
    wg.Wait()
}

Running this code will result in the following error:

finish download
finish download
panic: sync: negative WaitGroup counter

goroutine 203 [running]:
sync.(*WaitGroup).Add(0xc00012e650, 0xffffffffffffffff)
	/usr/local/go/src/sync/waitgroup.go:74 +0x137
sync.(*WaitGroup).Done(0xc00012e650)
	/usr/local/go/src/sync/waitgroup.go:99 +0x34
main.download(0xa5, 0x0, 0xa6, 0x68d680, 0x3e, 0xc0000789f0, 0xc0000788d0)
	/home/chenmei/go/src/test/waitgroup.go:22 +0x359
created by main.main
	/home/chenmei/go/src/test/waitgroup.go:30 +0xa3
exit status 2

This error is caused by the negative reference count in the process of delivery. The value of sync.WaitGroup passed in the process of delivery forms a copy, so the object used in the process of delivery is actually a copy. Therefore, when the Done method is executed, it is the operation of the copy object, which has no effect on the wg in the main method

Tags: Programming

Posted on Tue, 03 Dec 2019 10:29:52 -0500 by mr00047