sync.Cond是Go中的另一个有用的并发组件。 它提供了一种在goroutine之间进行通信的方法,而无需通过显式的信号来同步它们。sync.Cond可以被认为是基于条件变量的并发原语。
sync.Cond在sync包中定义,并通过sync.NewCond函数创建。它需要一个sync.Mutex作为其底层锁。
以下是sync.Cond的一些方法:
func (c *Cond) Wait()
让goroutine进入等待状态,并在条件变量满足时被唤醒。
func (c *Cond) Signal()
唤醒至少一个正在等待条件变量的goroutine。
func (c *Cond) Broadcast()
唤醒所有正在等待条件变量的goroutine。
sync.Cond通常用于等待特定条件的goroutine之间的通信。以下是一个示例,其中一个goroutine生产整数,另一个goroutine消费整数,当生产的整数满足特定条件时,消费者goroutine将被唤醒:
package main
import (
"fmt""math/rand""sync""time"
)
var (
cond *sync.Cond
shared int
)
funcproducer() {
for {
// 生成随机整数
n := rand.Intn(100)
fmt.Printf("Produced: %d\n", n)
// 加锁并更新共享变量
cond.L.Lock()
shared = n
// 通知等待的消费者
cond.Signal()
cond.L.Unlock()
time.Sleep(time.Second)
}
}
funcconsumer() {
for {
// 加锁并检查条件
cond.L.Lock()
for shared%10 != 0 {
// 等待条件
cond.Wait()
}
// 消费共享变量
fmt.Printf("Consumed: %d\n", shared)
cond.L.Unlock()
time.Sleep(time.Second)
}
}
funcmain() {
// 创建互斥锁和条件变量
mutex := &sync.Mutex{}
cond = sync.NewCond(mutex)
// 启动生产者和消费者go producer()
go consumer()
// 等待一段时间,然后退出
time.Sleep(10 * time.Second)
}
使用场景
可以用于协调多个 goroutine 的执行顺序。在某些场景下,多个 goroutine 需要等待某个条件成立之后才能继续执行,这时候可以使用条件变量来协调它们的执行。
一个常见的应用场景是生产者-消费者模型,生产者在一个 channel 中生成数据,消费者在另外一个 channel 中接收数据并进行处理。当生产者生成的数据达到一定的数量时,就需要通知消费者开始处理数据。这时候可以使用 sync.Cond 来协调它们的执行。示例代码如下:
package main
import (
"fmt"
"sync"
)
func main() {
var (
mu sync.Mutex
cv = sync.NewCond(&mu)
)
const (
numWorkers = 3
maxJobs = 10
)
var (
jobs = make(chanint, maxJobs)
done = make(chanstruct{}, numWorkers)
numJobs = 0
numDone = 0
numFailed = 0
)
for i := 0; i < numWorkers; i++ {
gofunc() {
for {
job, ok := <-jobs
if !ok {
break
}
// 模拟一些处理
if job%2 == 0 {
fmt.Printf("job %d processed\n", job)
} else {
fmt.Printf("job %d failed\n", job)
mu.Lock()
numFailed++
mu.Unlock()
}
// 处理完成后通知
cv.Broadcast()
}
done <- struct{}{}
}()
}
go func() {
for i := 0; i < maxJobs; i++ {
mu.Lock()
for numJobs >= maxJobs/2 {
cv.Wait()
}
jobs <- i
numJobs++
mu.Unlock()
}
close(jobs)
}()
for numDone < numWorkers {
<-done
numDone++
}
fmt.Printf("done with %d successful jobs and %d failed jobs\n", maxJobs-numFailed, numFailed)
}
在这个例子中,有三个 goroutine 充当消费者的角色,它们从 jobs channel 中接收数据进行处理。在生产者的 goroutine 中,使用条件变量 cv 来协调生产者和消费者的执行。当 numJobs 超过了 maxJobs/2 时,生产者会阻塞等待条件变量的信号