go协程同步的三种方式

1.Mutex   2.channel   3.WaitGroup

 

1.使用锁的方式

 1 package main
 2 
 3 import (
 4     "fmt"
 5     "sync"
 6     "time"
 7 )
 8 
 9 var share_cnt uint64 = 0
10 
11 var lck sync.Mutex
12 
13 func incrShareCnt() {
14     for i := 0; i < 1000000; i++ {
15         lck.Lock()
16         share_cnt++ //共有资源
17         lck.Unlock()
18     }
19     fmt.Println(share_cnt)
20 }
21 func main() {
22     for i := 0; i < 2; i++ {
23         go incrShareCnt()
24     }
25     time.Sleep(1 * time.Second) //1秒
26 }

2.使用channel通道可以用来作为消息机制也可作为锁机制

  1.有缓冲/无缓冲channel

无缓冲的channel只能发送完之后协程立马阻塞,只有等有协程接受了之后才能继续发送,

等待协程接受了,之后立马阻塞,等待channel中有数据才会启动

 1 package main
 2 
 3 import (
 4     "fmt"
 5     "time"
 6 )
 7 
 8 func main() {
 9     c := make(chan int) //声明一个int类型的无缓冲通道
10     go func() {
11         fmt.Println("准备发送1数据")
12         c <- 1
13         fmt.Println("发送1数据完毕")
14         fmt.Println("协程开始睡眠1秒")
15         time.Sleep(time.Second)
16         fmt.Println("协程结束睡眠")
17         c <- 2
18         fmt.Println("发送2数据完毕")
19     }()
20 
21     fmt.Println("主线程休眠1秒")
22     time.Sleep(time.Second)
23     fmt.Println("主线程结束休眠")
24     i := <-c
25     fmt.Printf("接受 %d\n", i)
26     i = <-c
27     fmt.Printf("接受 %d\n", i)
28     time.Sleep(time.Second)
29 }

1//运行结果 
主线程休眠1秒 2 准备发送1数据 3 主线程结束休眠 4 发送1数据完毕 5 协程开始睡眠1秒 6 接受 1 7 协程结束睡眠 8 发送2数据完毕 9 接受

 注意:

func main() {
	c := make(chan int)		//声明一个int类型的无缓冲通道
	c <- 1
	i := <- c
	fmt.Printf("receive %d\n", i)
}会报错
在同一个线程里进行channel读写操作会发生死锁

有缓冲的channel阻塞条件不同:当缓冲区满了发送线程阻塞,缓冲区空了接受线程阻塞
 1 package main
 2 
 3 import (
 4     "fmt"
 5     "time"
 6 )
 7 
 8 func main() {
 9     c := make(chan int, 2) //声明一个int类型的有缓冲通道
10     go func() {
11         for i := 0; i < 4; i++ {
12             c <- i
13             fmt.Printf("send %d\n", i)
14         }
15         time.Sleep(5 * time.Second)
16         for i := 4; i < 6; i++ {
17             c <- i
18             fmt.Printf("send %d\n", i)
19         }
20     }()
21 
22     for i := 0; i < 6; i++ {
23         time.Sleep(time.Second)
24         fmt.Printf("receive %d\n", <-c)
25     }
26 }
send 0
send 1
receive 0
send 2
receive 1
send 3
receive 2
receive 3
send 4
send 5
receive 4
receive 5
3.WaitGroup函数的使用
 1 package main
 2 import (
 3     "fmt"
 4     "sync"
 5 )
 6 func main() {
 7     fmt.Println("Hello World")
 8     var waitgroup sync.WaitGroup
 9     waitgroup.Add(1)
10     go myFunc(&waitgroup)
11     waitgroup.Wait()
12     fmt.Println("Finished Execution")
13 }
14 func myFunc(waitgroup *sync.WaitGroup) {
15     fmt.Println("Inside my goroutine")
16     waitgroup.Done()
17 }

上面代码输出结果为:

Hello World
Inside my goroutine
Finished Execution

达到了我们想要的结果。

接下来对上面的代码做一些解释:

我们在开启协程之前,先调用了WaitGroup的Add(1)方法,是要设置主函数需要等待完成的协程数为1,Wait()方法是等待协程的完成。我们在协程中调用的WaitGroup的Done()方法,意思是当前协程执行完成(Done()做的工作其实就是把需要等待的协程个数减1),当需要等待的协程数为0时,则不需要再等待,继续执行以下的代码。


posted @ 2021-03-06 23:27  爱晒太阳的懒猫。。  阅读(360)  评论(0编辑  收藏  举报