使goroutine同步的方法总结

简介:

使goroutine同步的方法总结

前言:

在前面并发性能对比的文章中,我们可以看到Golang处理大并发的能力十分强劲,而且开发也特别方便,只需要用go关键字即可开启一个新的协程。

但当多个goroutine同时进行处理的时候,就会遇到同时抢占一个资源的情况(并发都会遇到的问题),所以我们希望某个goroutine等待另一个goroutine处理完某一个步骤之后才能继续。sync包就是为了让goroutine同步而出现的。当然还可以使用channel实现,这个后面会介绍到。

锁:

锁有两种:互斥锁(mutex)和读写锁(RWMutex)

互斥锁: 当数据被加锁了之后,除次外的其他协程不能对数据进行读操作和写操作。 这个当然能解决并发程序对资源的操作。但是,效率上是个问题,因为当加锁后,其他协程只有等到解锁后才能对数据进行读写操作。

读写锁: 读数据的时候上读锁,写数据的时候上写锁。有写锁的时候,数据不可读不可写。有读锁的时候,数据可读,不可写。

两种锁的使用方式相同,这里就只列出互斥锁的代码:

 1package main 2 3import ( 4  "sync" 5  "time" 6  "fmt" 7) 8 9var num = 01011func main ()  {12  mu := &sync.Mutex{}13  for i:=0;i<10000;i++ {14    go func(){15      mu.Lock()16      defer mu.Unlock()17      num += 118    }()19  }20  time.Sleep(time.Second)21  fmt.Println("num:", num)  // 如果不加锁这里的num的值会是一个随机数而不是1000022}
AI 代码解读

Once:

有的时候,我们启动多个相同goroutine,但是里面的某个操作我只希望被执行一次,这个时候Once就上场了。

 1package
 1package 2 3 4import ( 5  "fmt" 6  "sync" 7  "time" 8) 910func main() {11  var once sync.Once12  one := func() {13    fmt.Println("just once")14  }1516  for i := 0; i < 10; i++ {17    go func(a int) {18      once.Do(one)   // 只是被执行一次19    }(i)20  }21  time.Sleep(time.Millisecond*200)22}
AI 代码解读

WaitGroup:

当某个操作或是某个goroutine需要等待一批goroutine执行完毕以后才继续执行,那么这种多线程(go里面说的线程就是goroutine)等待的问题就可以使用WaitGroup了。

代码如下:

 1package main 2 3import ( 4    "sync" 5    "fmt" 6    "time" 7) 8 9var waitGroup sync.WaitGroup1011func main () {12    for i := 0; i < 10; i++ {13        waitGroup.Add(1)  // 添加需要等待goroutine的数量14        go func() {15            fmt.Println("hehe")16            time.Sleep(time.Second)17            waitGroup.Done() // 减少需要等待goroutine的数量 相当于Add(-1)18        } ()19    }2021    waitGroup.Wait()  // 执行阻塞,直到所有的需要等待的goroutine数量变成022    fmt.Println("over")23}
AI 代码解读

Cond:

sync.Cond是用来控制某个条件下,goroutine进入等待时期,等待信号到来,然后重新启动。

代码如下:

 1package main 2 3import ( 4    "fmt" 5    "sync" 6    "time" 7) 8var locker = new(sync.Mutex) 9var cond = sync.NewCond(locker)1011func test(x int) {12    cond.L.Lock() //获取锁13    cond.Wait()//等待通知 暂时阻塞14    fmt.Println(x)15    time.Sleep(time.Second * 1)16    cond.L.Unlock()//释放锁17}18func main() {19    for i := 0; i < 40; i++ {20        go test(i)21    }22    fmt.Println("start all")23    time.Sleep(time.Second * 3)24    fmt.Println("signal1")25    cond.Signal()   // 下发一个通知随机给已经获取锁的goroutine26    time.Sleep(time.Second * 3)27    fmt.Println("signal2")28    cond.Signal()// 下发第二个通知随机给已经获取锁的goroutine29    time.Sleep(time.Second * 1)  // 在广播之前要等一会,让所有线程都在wait状态30    fmt.Println("broadcast")31    cond.Broadcast()//下发广播给所有等待的goroutine32    time.Sleep(time.Second * 60)33}
AI 代码解读

上面代码有几个要点要特别说明一下:

1. 每个Cond都必须有个与之关联的锁  // 见第9行

2. 协程方法里面一开始/结束都必须加/解锁 // 见第12行和16行

3. cond.Wait()时会自动解锁,当被唤醒时,又会加上锁。所以第2点提到必须加/解锁。

Channel

channel不仅可以用来goroutine之间的通信,也可以使goroutine同步完成协作。这点主要基于从channel取数据的时候,会阻塞当前goroutine这个特性。示例代码如下:

 1package main 2 3import ( 4    "fmt" 5    "time" 6) 7 8 9var chan1 = make(chan string512)1011var arr1 = []string{"qq","ww","ee","rr","tt"}1213func chanTest1() {14    for _, v := range arr1 {15        chan1 <- v16    }17    close(chan1) // 关闭channel18}1920func chanTest2() {21    for {22        getStr, ok := <- chan1  // 阻塞,直到chan1里面有数据23        if !ok {   // 判断channel是否关闭或者为空24            return25        }26        fmt.Println(getStr) // 按数组顺序内容输出27    }28}2930func main () {31    go chanTest1()32    go chanTest2()3334    time.Sleep(time.Millisecond*200)35}
AI 代码解读


原文发布时间为:2018-10-8

本文来自云栖社区合作伙伴“Golang语言社区”,了解相关信息可以关注“Golang语言社区”。

目录
打赏
0
0
0
0
73530
分享
相关文章
阻塞式/非阻塞式与同步/异步的区别
阻塞式/非阻塞式与同步/异步的区别
130 0
阻塞/阻塞/同步/异步
咱就说有没有一种可能,同步、异步、阻塞、非阻塞,这几个关键词拆开看都感觉挺明白的。但是同步阻塞、同步非阻塞、异步阻塞、异步非阻塞,这几个关键词组装起来,看起来就有点那么晦涩了。这个在日常八股中经常出现字眼,其背后对应的到底是个什么样的逻辑?我们来一起揭开它那不那么神秘的面纱。/手动狗头。
133 0
阻塞/阻塞/同步/异步
线程的同步
线程的同步
143 0
同步 异步 阻塞 非阻塞
在高性能的IO体系设计中,有几个名词概念常常会使我们感到迷惑不解。具体如下:  序号 问题 1 什么是同步? 2 什么是异步? 3 什么是阻塞? 4 什么是非阻塞? 5 什么是同步阻塞? 6 什么是同步非阻塞? 7 什么是异步阻塞? 8 什么是异步非阻塞? 散仙不才,在查了一部分资料后,愿试着以通俗易懂的方式
1905 1
同步、异步、阻塞、非阻塞
同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication) 真正意义上的 异步IO 是说内核直接将数据拷贝至用户态的内存单元,再通知程序直接去读取数据。
1022 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等