当几个goroutine同时进行,须要等待这几个协程完成以后再作其余的操做.url
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是没有做用的.协程