「Go语言进阶」并发编程详解( 三 )

1.4 并发安全 Lock在并发编程中 , 当多个 goroutine 同时访问共享资源时 , 可能会出现竞争条件 , 导致数据不一致或错误 。为了避免这种情况 , 我们可以使用 Lock(锁)来保证并发安全 。
Lock 是一种同步机制 , 可以防止多个 goroutine 同时访问共享资源 。当一个 goroutine 获取锁时 , 其他 goroutine 将被阻塞 , 直到锁被释放 。
Go语言标准库中提供了 sync.Mutex 来实现锁 。
一个简单的例子:
 package mainimport ("fmt""sync")var (count intlocksync.Mutex)func main() {wg := sync.WaitGroup{}for i := 0; i < 10; i++ {wg.Add(1)go func() {defer wg.Done()lock.Lock()defer lock.Unlock()count++fmt.Println(count)}()}wg.Wait()}执行效果:
 

「Go语言进阶」并发编程详解

文章插图
 
在上面的示例中 , main函数中启动了10个goroutine , 每个goroutine都会尝试去获取锁 , 并对共享变量count进行修改 。在获取锁后才能进行修改 , 其他goroutine在等待锁时将被阻塞 。
这样就能保证并发安全了 , 使得共享变量count在多个goroutine之间可以安全地访问 。但是 , 使用锁也需要注意避免死锁的情况 , 需要在适当的时候释放锁 。并发安全问题难以定位 。
1.5 WaitGroupGo语言标准库中提供了 sync.WaitGroup 来管理多个 goroutine 的执行 。
  • Add(delta int): 使用该方法来增加等待组中 goroutine 的数量 。当我们需要等待一些 goroutine 执行完毕时 , 就可以使用该方法来增加等待组中 goroutine 的数量 。
  • Done(): 使用该方法来通知等待组 , 一个 goroutine 执行完毕 。当一个 goroutine 执行完毕后 , 我们需要调用该方法来通知等待组 。
  • Wait(): 使用该方法来等待等待组中的所有 goroutine 执行完毕 。当我们需要等待所有 goroutine 执行完毕时 , 就可以使用该方法 。
下面是一个例子 , 演示了如何使用 sync.WaitGroup 来管理多个 goroutine 的执行:
 package mainimport ("fmt""sync")func main() {var wg sync.WaitGroupwg.Add(3) //增加3个goroutinego func() {defer wg.Done()fmt.Println("Goroutine 1")}()go func() {defer wg.Done()fmt.Println("Goroutine 2")}()go func() {defer wg.Done()fmt.Println("Goroutine 3")}()wg.Wait()fmt.Println("all goroutines have been finished")}执行效果:
 
「Go语言进阶」并发编程详解

文章插图
 
在上面的代码中 , 我们使用了 sync.WaitGroup 来管理三个 goroutine 的执行 。我们先使用 wg.Add(3) 来增加等待组中 goroutine 的数量 。然后在每个 goroutine 中调用 wg.Done() 来通知等待组 , 该 goroutine 执行完毕 。最后使用 wg.Wait() 来等待所有 goroutine 执行完毕 。
注意:
  • 如果没有 wg.Wait() , 主协程可能会在其他协程还没有执行完成的情况下结束 , 这样的话其他协程的执行结果就没有机会被获取 。
  • 如果Add的数量和done的数量不对应 , wait永远不会返回 , 这也叫死锁 。
在线运行 
「Go语言进阶」并发编程详解

文章插图
 
上面分享的代码都支持 , 访问下方链接运行测试:https://1024code.com/codecubes/GB47x7u
本文转载自微信公众号「 程序员升级打怪之旅」 , 作者「王中阳Go」




推荐阅读