go等待一組協(xié)程結(jié)束的操作方式
go提供了sync包和channel來(lái)解決協(xié)程同步和通訊。
方式1:
sync.WaitGroup是等待一組協(xié)程結(jié)束,sync.WaitGroup只有3個(gè)方法,Add()添加一個(gè)計(jì)數(shù),Done()減去一個(gè)計(jì)數(shù),Wait()阻塞直到所有任務(wù)完成。
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup //定義一個(gè)同步等待的組
func task(i int){
fmt.Println("task...",i)
//耗時(shí)操作任務(wù),網(wǎng)絡(luò)請(qǐng)求,讀取文件
time.Sleep(time.Second)
wg.Done() //減去一個(gè)計(jì)數(shù)
}
func main(){
for i:= 0;i<10;i++{
wg.Add(1) //添加一個(gè)計(jì)數(shù)
go task(i)
}
wg.Wait() //阻塞直到所有任務(wù)完成
fmt.Println("over")
}
運(yùn)行結(jié)果:
task... 9
task... 4
task... 6
task... 0
task... 7
task... 5
task... 1
task... 2
task... 8
task... 3
over
方式2:
利用緩沖信道channel協(xié)程之間通訊,其阻塞等待功能實(shí)現(xiàn)等待一組協(xié)程結(jié)束,不能保證其goroutine按照順序執(zhí)行
package main
import (
"fmt"
)
var ch = make(chan int,10)
func task(i int){
fmt.Println("task...",i)
ch <- i
}
func main(){
for i:= 0;i<10;i++{
go task(i)
}
for i:= 0;i<10;i++{
<- ch
}
fmt.Println("over")
}
運(yùn)行結(jié)果:
task... 9
task... 0
task... 1
task... 2
task... 6
task... 7
task... 3
task... 4
task... 8
task... 5
over
方式3:
利用無(wú)緩沖的信道channel協(xié)程之間通訊,其阻塞等待功能實(shí)現(xiàn)等待一組協(xié)程結(jié)束,保證了其goroutine按照順序執(zhí)行
package main
import (
"fmt"
"time"
)
var ch = make(chan int)
func task(i int){
fmt.Println("task...",i)
time.Sleep(time.Second)
<- ch
}
func main(){
for i:= 0;i<10;i++{
go task(i)
ch <- i
}
fmt.Println("over")
}
運(yùn)行結(jié)果:
task... 0
task... 1
task... 2
task... 3
task... 4
task... 5
task... 6
task... 7
task... 8
task... 9
over
補(bǔ)充:Go中使用Channel等待所有協(xié)程結(jié)束
讓main方法等待所有協(xié)程執(zhí)行完畢再退出。可能一般思路是設(shè)置一個(gè)共有變量,然后通過(guò)修改這個(gè)變量的狀態(tài)。這是通過(guò)共享變量來(lái)通信的方式,而go要做的是,通過(guò)通信來(lái)共享內(nèi)存。
1. 按順序執(zhí)行
每次通信進(jìn)行成對(duì)通信,當(dāng)main向協(xié)程發(fā)送一個(gè)寫(xiě)channel時(shí),同時(shí)也等待協(xié)程返回一個(gè)讀channel。
這兩個(gè)channel一定是成對(duì)的,所以構(gòu)造一個(gè)結(jié)構(gòu)體
type worker struct {
in chan int
done chan bool
}
func chanDemo1(){
var workers [10]worker
for i := 0; i < 10; i++ {
workers[i] = createWorker1(i)
}
for i := 0; i < 10; i++ {
workers[i].in <- 'a' + i
<- workers[i].done
}
for i := 0; i < 10; i++ {
workers[i].in <- 'A' + i
<- workers[i].done
}
}
func createWorker1(id int) worker {
work := worker{
in: make(chan int),
done: make(chan bool),
}
go func() {
for {
fmt.Printf("Work %d receiverd %c\n", id, <- work.in)
work.done <- true
}
}()
return work
}
func main(){
chanDemo1()
fmt.Println("over")
}
這個(gè)執(zhí)行結(jié)果完全是按照0-9,先小寫(xiě)再大寫(xiě)的順序
如果這樣順序執(zhí)行,還要協(xié)程干啥
2. 批量處理
type worker struct {
in chan int
done chan bool
}
func chanDemo1(){
var workers [10]worker
for i := 0; i < 10; i++ {
workers[i] = createWorker1(i)
}
for i := 0; i < 10; i++ {
workers[i].in <- 'a' + i
}
for _, worker := range workers {
<- worker.done
}
for i := 0; i < 10; i++ {
workers[i].in <- 'A' + i
}
for _, worker := range workers {
<- worker.done
}
}
func createWorker1(id int) worker {
work := worker{
in: make(chan int),
done: make(chan bool),
}
go func() {
for {
fmt.Printf("Work %d receiverd %c\n", id, <- work.in)
work.done <- true
}
}()
return work
}
這樣的話,先打印小寫(xiě),再打印大寫(xiě),但是大小寫(xiě)時(shí)順序不固定
3. 完全隨機(jī)
func chanDemo1(){
var workers [10]worker
for i := 0; i < 10; i++ {
workers[i] = createWorker1(i)
}
for i := 0; i < 10; i++ {
workers[i].in <- 'a' + i
}
for i := 0; i < 10; i++ {
workers[i].in <- 'A' + i
}
for _, worker := range workers {
<- worker.done
<- worker.done
}
}
func createWorker1(id int) worker {
work := worker{
in: make(chan int),
done: make(chan bool),
}
go func() {
for {
fmt.Printf("Work %d receiverd %c\n", id, <- work.in)
// 再開(kāi)一個(gè)協(xié)程
go func() { work.done <- true}()
}
}()
return work
}
這種方式就是完全隨機(jī)了
使用channel進(jìn)行樹(shù)的遍歷
func (node *Node) TraverseFunc(f func(*Node)){
if node == nil{
return
}
node.Left.TraverseFunc(f)
f(node)
node.Right.TraverseFunc(f)
}
func (node *Node) TraverseWithChannel() chan *Node{
out := make(chan *Node)
go func() {
node.TraverseFunc(func(node *Node) {
out <- node
})
close(out)
}()
return out
}
func main(){
var root Node
root = Node{Value:3}
root.Left = &Node{}
root.Right = &Node{5,nil,nil}
root.Right.Left = new(Node)
root.Left.Right =&Node{6,nil,nil}
root.Traverse()
c:=root.TraverseWithChannel()
maxNode := 0
for node := range c{
if node.Value > maxNode{
maxNode = node.Value
}
}
fmt.Println("max node value:", maxNode)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
Go語(yǔ)言做爬蟲(chóng)狀態(tài)碼返回418的問(wèn)題解決
在使用Go語(yǔ)言做爬蟲(chóng)時(shí),使用http.Get(url)去獲取網(wǎng)頁(yè)內(nèi)容,狀態(tài)碼返回404,本文我們就詳細(xì)的介紹一下解決方法,感興趣的可以了解一下2021-12-12
Go語(yǔ)言獲取本機(jī)邏輯CPU數(shù)量的方法
這篇文章主要介紹了Go語(yǔ)言獲取本機(jī)邏輯CPU數(shù)量的方法,實(shí)例分析了runtime庫(kù)的操作技巧,需要的朋友可以參考下2015-03-03
Go語(yǔ)言實(shí)現(xiàn)登錄驗(yàn)證代碼案例
這篇文章主要介紹了Go語(yǔ)言實(shí)現(xiàn)登錄驗(yàn)證代碼案例,代碼和圖文講解的很清晰,有感興趣的可以學(xué)習(xí)下2021-03-03
golang 中string和int類型相互轉(zhuǎn)換
這篇文章主要介紹了golang 中string和int類型相互轉(zhuǎn)換,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
使用Go和Gorm實(shí)現(xiàn)讀取SQLCipher加密數(shù)據(jù)庫(kù)
本文檔主要描述通過(guò)Go和Gorm實(shí)現(xiàn)生成和讀取SQLCipher加密數(shù)據(jù)庫(kù)以及其中踩的一些坑,文章通過(guò)代碼示例講解的非常詳細(xì), 對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-06-06
Go語(yǔ)言range關(guān)鍵字循環(huán)時(shí)的坑
今天小編就為大家分享一篇關(guān)于Go語(yǔ)言range關(guān)鍵字循環(huán)時(shí)的坑,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-03-03
使用client-go工具調(diào)用kubernetes API接口的教程詳解(v1.17版本)
這篇文章主要介紹了使用client-go工具調(diào)kubernetes API接口(v1.17版本),本文通過(guò)圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-08-08

