sync.WaitGroup在协程中的使用

使用的场景:

当几个goroutine同时进行,需要等待这几个协程完成之后再做其他的操作.

使用的步骤:

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

运行这个代码将出现如下错误:

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是没有作用的.

转载于:https://my.oschina.net/u/1013544/blog/3029150

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值