Go中sync包Cond使用场景是什么
更新时间:2023-11-29Cond是什么?
Cond是Go中sync包的一个结构体类型,它提供了一种基于条件变量的线程同步机制,可以用来等待或通知Goroutine。
Cond类型的定义如下:
type Cond struct { L Locker // contains filtered or unexported fields }
其中L是接口Locker,可以是任何类型满足一定接口。Locker接口只有两个方法:Lock和Unlock,代表着锁定和解锁操作。
Cond的使用场景
Cond通常用于需要线程同步的场景,例如多个Goroutine需要等待某个事件(或共享资源)完成后再进行操作。例如,如果一个计算任务需要输入数据进行计算,那么需要先确保数据已经就绪,然后再启动多个Goroutine进行计算。
下面是一个使用Cond实现的例子:多个Goroutine同时等待一个资源调度:
package main import ( "fmt" "sync" "time" ) func main() { var wg sync.WaitGroup var m sync.Mutex cond := sync.NewCond(&m) ready := false //启动5个Goroutine等待调度 for i := 0; i < 5; i++ { wg.Add(1) go func(id int) { defer wg.Done() m.Lock() for !ready { cond.Wait() } fmt.Printf("Goroutine %d do something...\n", id) m.Unlock() }(i) } //模拟资源调度 time.Sleep(time.Second) m.Lock() ready = true cond.Broadcast() m.Unlock() //等待所有Goroutine结束 wg.Wait() }
这段代码中,启动了5个Goroutine,在调度前一直处于等待状态,调度完成后才开始执行。其中Wait方法会在等待前自动进行解锁操作,避免了死锁。
Cond的方法
Cond提供了三个方法:
- Wait:等待条件变量满足。
- Broadcast:广播通知所有等待者条件变量已经满足,由此唤醒所有等待者。
- Signal:通知任意一个等待者条件变量已经满足,由此唤醒一个等待者。
三个方法都需要在加锁状态下使用。
下面是实现一个生产者-消费者模型的例子,演示了Wait和Signal的使用:
package main import ( "fmt" "sync" "time" ) func main() { var wg sync.WaitGroup var m sync.Mutex cond := sync.NewCond(&m) queue := make([]int, 0, 10) //启动5个生产者 for i := 0; i < 5; i++ { wg.Add(1) go func(id int) { defer wg.Done() for { //生产一个随机数 num := int(time.Now().UnixNano() % 100) m.Lock() //如果队列满了,等待消费者处理 for len(queue) == cap(queue) { cond.Wait() } //将数据放入队列 queue = append(queue, num) fmt.Printf("Producer %d produce %d, queue: %v\n", id, num, queue) //通知一个等待的消费者 cond.Signal() m.Unlock() time.Sleep(time.Millisecond * 500) } }(i) } //启动1个消费者 wg.Add(1) go func() { defer wg.Done() for { m.Lock() //如果队列为空,等待生产者生产 for len(queue) == 0 { cond.Wait() } //取出队列第一个数据 num := queue[0] queue = queue[1:] fmt.Printf("Consumer consume %d, queue: %v\n", num, queue) //通知一个等待的生产者 cond.Signal() m.Unlock() time.Sleep(time.Millisecond * 1000) } }() //等待所有Goroutine结束 wg.Wait() }
这段代码中,启动了5个生产者和1个消费者,其中生产者会按固定时间随机生成一个整数,并添加到队列中,队列满时会等待消费者处理。消费者会从队列中取出第一个数据进行处理,队列为空时会等待生产者生成新数据。其中Wait和Signal的使用使得生产和消费能够高效地进行。
总结
Cond是Go中一种非常实用的线程同步工具,提供了基于条件变量的线程同步机制,可以用于等待或通知Goroutine。使用Cond可以有效避免死锁和资源浪费,提高程序的效率。使用时需要注意加锁和解锁状态,避免竞争。