go提供了sync包和channel來解決協程同步和通訊。
方式1:
sync.WaitGroup是等待一組協程結束,sync.WaitGroup只有3個方法,Add()添加一個計數,Done()減去一個計數,Wait()阻塞直到所有任務完成。
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup //定義一個同步等待的組
func task(i int){
fmt.Println("task...",i)
//耗時操作任務,網絡請求,讀取文件
time.Sleep(time.Second)
wg.Done() //減去一個計數
}
func main(){
for i:= 0;i10;i++{
wg.Add(1) //添加一個計數
go task(i)
}
wg.Wait() //阻塞直到所有任務完成
fmt.Println("over")
}
運行結果:
task... 9
task... 4
task... 6
task... 0
task... 7
task... 5
task... 1
task... 2
task... 8
task... 3
over
方式2:
利用緩沖信道channel協程之間通訊,其阻塞等待功能實現等待一組協程結束,不能保證其goroutine按照順序執行
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;i10;i++{
go task(i)
}
for i:= 0;i10;i++{
- ch
}
fmt.Println("over")
}
運行結果:
task... 9
task... 0
task... 1
task... 2
task... 6
task... 7
task... 3
task... 4
task... 8
task... 5
over
方式3:
利用無緩沖的信道channel協程之間通訊,其阻塞等待功能實現等待一組協程結束,保證了其goroutine按照順序執行
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;i10;i++{
go task(i)
ch - i
}
fmt.Println("over")
}
運行結果:
task... 0
task... 1
task... 2
task... 3
task... 4
task... 5
task... 6
task... 7
task... 8
task... 9
over
補充:Go中使用Channel等待所有協程結束
讓main方法等待所有協程執行完畢再退出。可能一般思路是設置一個共有變量,然后通過修改這個變量的狀態。這是通過共享變量來通信的方式,而go要做的是,通過通信來共享內存。
1. 按順序執行
每次通信進行成對通信,當main向協程發送一個寫channel時,同時也等待協程返回一個讀channel。
這兩個channel一定是成對的,所以構造一個結構體
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")
}
這個執行結果完全是按照0-9,先小寫再大寫的順序
如果這樣順序執行,還要協程干啥
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
}
這樣的話,先打印小寫,再打印大寫,但是大小寫時順序不固定
3. 完全隨機
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)
// 再開一個協程
go func() { work.done - true}()
}
}()
return work
}
這種方式就是完全隨機了
使用channel進行樹的遍歷
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)
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。如有錯誤或未考慮完全的地方,望不吝賜教。
您可能感興趣的文章:- Go遞歸修改文件名的實例代碼
- go build 通過文件名后綴實現不同平臺的條件編譯操作
- Go并發:使用sync.WaitGroup實現協程同步方式
- SpringBoot整合MongoDB實現文件上傳下載刪除
- golang協程池模擬實現群發郵件功能
- Go 如何批量修改文件名