下面是“Go语言通过WaitGroup实现控制并发的示例详解”的完整攻略。
简介
在并发编程中,我们经常需要协调多个goroutine的执行顺序,有可能需要等待一组goroutine全部执行完成才能进行下一步操作。Go语言提供了sync.WaitGroup
来实现这样的控制,并发的方法。
sync.WaitGroup
用于等待一组goroutine的执行,我们可以使用sync.WaitGroup
来等待所有的goroutine都执行完成后再执行后面的代码。
使用WaitGroup
- 初始化WaitGroup
首先需要新建一个sync.WaitGroup
类型的变量,这个变量用来记录goroutine的数量:
var wg sync.WaitGroup
- 添加goroutine数量
通过调用Add
方法向WaitGroup
中添加goroutine的数量:
wg.Add(2)
- 启动goroutine
接下来,需要启动多个goroutine,在goroutine结束时调用WaitGroup
的Done
方法,通知WaitGroup
有一个goroutine已结束:
go func() {
defer wg.Done()
// 业务逻辑
}()
go func() {
defer wg.Done()
// 业务逻辑
}()
- 等待所有goroutine执行完成
最后,需要在程序的入口处调用WaitGroup
的Wait
方法,等待所有goroutine执行完成:
wg.Wait()
示例1:并发下载多个文件
我们可以使用上面的方法实现一个并发下载多个文件的示例。
package main
import (
"fmt"
"io/ioutil"
"net/http"
"sync"
)
func main() {
urls := []string{
"http://example.com/file1.txt",
"http://example.com/file2.txt",
"http://example.com/file3.txt",
"http://example.com/file4.txt",
"http://example.com/file5.txt",
}
var wg sync.WaitGroup
for _, url := range urls {
wg.Add(1)
go func(url string) {
defer wg.Done()
resp, err := http.Get(url)
if err != nil {
fmt.Printf("get %s error: %v\n", url, err)
return
}
defer resp.Body.Close()
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("read %s error: %v\n", url, err)
return
}
fmt.Printf("%s length:%d\n", url, len(content))
}(url)
}
wg.Wait()
fmt.Println("all done")
}
示例2:控制并发数量
在某些情况下,我们可能需要控制并发量。例如,在下载多个文件时,我们不希望同时下载过多的文件导致网络拥堵。我们可以使用一个计数器实现这个功能,当下载的goroutine数量超过指定的值时,等待已经下载完成的goroutine,以保证同时下载的goroutine数量不会过多。
package main
import (
"fmt"
"io/ioutil"
"net/http"
"sync"
)
func main() {
urls := []string{
"http://example.com/file1.txt",
"http://example.com/file2.txt",
"http://example.com/file3.txt",
"http://example.com/file4.txt",
"http://example.com/file5.txt",
}
maxWorkers := 2 // 最大并发数量
workers := 0 // 当前并发数量
var wg sync.WaitGroup
for _, url := range urls {
wg.Add(1)
for workers >= maxWorkers {
// 当前并发量超过最大并发量,等待一个下载完成
wg.Done()
workers--
}
workers++
go func(url string) {
defer wg.Done()
resp, err := http.Get(url)
if err != nil {
fmt.Printf("get %s error: %v\n", url, err)
return
}
defer resp.Body.Close()
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("read %s error: %v\n", url, err)
return
}
fmt.Printf("%s length:%d\n", url, len(content))
}(url)
}
for workers > 0 {
// 等待并发量恢复到0
wg.Done()
workers--
}
wg.Wait()
fmt.Println("all done")
}
以上就是关于“Go语言通过WaitGroup实现控制并发的示例详解”的完整攻略。通过sync.WaitGroup
的使用,我们可以更轻松地控制并发,提高程序执行效率。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Go语言通过WaitGroup实现控制并发的示例详解 - Python技术站