sync.WaitGroup在協程中的使用

使用的場景:

當幾個goroutine同時進行,須要等待這幾個協程完成以後再作其餘的操做.url

使用的步驟:

  1. 定義一個對象
    2.使用sync.WaitGroup的Add方法添加一個計數到隊列裏面 3.使用sync.WaitGroup的Done方法來通知一個協程已經完成 4.使用sync.WaitGroup的Wait方法等待協程的完成

使用實例:

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()
}

使用的時候須要注意的地方:

在協程的代碼中使用的sync.WaiteGroup的實例必定要是一個指針,不能傳遞值,若是傳遞值將致使由於引用數爲負數而報錯. 例如將上面的代碼改爲以下:指針

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()
}

運行這個代碼將出現以下錯誤:code

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

出現這個錯誤就是因爲協程中的引用計數成爲了負值而致使的錯誤. 在傳遞的過程當中傳遞的sync.WaitGroup的值,這樣就造成了一份拷貝,從而在協程中使用的對象實際上是一份拷貝. 因此當在執行Done方法的時候是對拷貝對象的操做,對main方法中的wg是沒有做用的.協程

相關文章
相關標籤/搜索