golang 系列:sync.Cond 机制

简介: 在 Go 里有专门为同步通信而生的 channel,所以较少看到 sync.Cond 的使用。不过它也是并发控制手段里的一种,今天我们就来认识下它的相关实现,加深对同步机制的运用。

前言

在 Go 里有专门为同步通信而生的 channel,所以较少看到 sync.Cond 的使用。不过它也是并发控制手段里的一种,今天我们就来认识下它的相关实现,加深对同步机制的运用。

sync.Cond

sync.Cond 提供了三个方法:Wait()、Signal()、Broadcast(),它们的用法如下:

  • Wait():阻塞当前的 goroutine,等待唤起。
  • Signal():唤起一个阻塞的 goroutine。
  • Broadcast():唤起所有阻塞的 goroutine。

通过上面的方法描述,我们就可以简单的实现一个任务池功能:先批量的创建 goroutine,然后调用 sync.Cond 的 Wait() 方法让其阻塞的等待。

当有一个任务到来时,则通过 Signal() 唤起刚刚在阻塞的某一个 goroutine,去执行任务。

通过任务池功能,我们发现 sync.Cond 的运用很简单,但 Go 官方并不推荐我们使用 sync.Cond 来实现协程间的同步通信

因为它并不符合 Go 官方 “通过通信来共享内存” 的设计思想,当场景复杂时,则会耦合各个业务功能。

sync.Cond 源码分析

我们来看下 sync.Cond 的结构体,代码在 /sr/sync/cond.go 下:

type Cond struct {
    noCopy noCopy         // 不可复制
    L Locker            // 锁
    notify  notifyList    // 通知唤起列表
    checker copyChecker // 复制检测
}

可以看到 Cond 上有 notify 列表,而这正是维护了需要唤起的 goroutine 列表。

当我们调用 Wait() 方法的时候就会维护当前 goroutine 到对应的 notifyList 里:

func (c *Cond) Wait() {
    c.checker.check()
    t := runtime_notifyListAdd(&c.notify) // 将当前 goroutine 添加到 notifyList 里
    c.L.Unlock()
    runtime_notifyListWait(&c.notify, t) // 阻塞等待
    c.L.Lock()
}

当有其他协程调用了 Signal 或 Broadcast 方法时,则会通过runtime_notifyListNotifyOneruntime_notifyListNotifyAll方法来唤起一个或多个 goroutine。

其他同步方式的实现

前面提到到 sync.Cond 并不被推荐作为协同通信手段,那如果要实现它的单播、广播效果,该怎么弄呢?

其实也很简单,如果我们要实现单播效果,那么只需要通过阻塞的监听 channel 信号即可。

如果要实现广播唤起效果,只需要利用 context 的链式取消特性,也能达到该效果。

相关文章
|
3月前
|
Go
浅谈Golang广播sync.Cond
浅谈Golang广播sync.Cond
73 0
|
3月前
|
存储 Go
Golang底层原理剖析之slice类型与扩容机制
Golang底层原理剖析之slice类型与扩容机制
46 0
|
12天前
|
监控 Go
|
6天前
|
人工智能 Go
深入理解 go sync.Cond
深入理解 go sync.Cond
13 0
|
3月前
|
负载均衡 算法 Go
Golang深入浅出之-Go语言中的服务注册与发现机制
【5月更文挑战第4天】本文探讨了Go语言中服务注册与发现的关键原理和实践,包括服务注册、心跳机制、一致性问题和负载均衡策略。示例代码演示了使用Consul进行服务注册和客户端发现服务的实现。在实际应用中,需要解决心跳失效、注册信息一致性和服务负载均衡等问题,以确保微服务架构的稳定性和效率。
59 3
|
3月前
|
Go 开发者
Golang深入浅出之-Go语言 defer、panic、recover:异常处理机制
Go语言中的`defer`、`panic`和`recover`提供了一套独特的异常处理方式。`defer`用于延迟函数调用,在返回前执行,常用于资源释放。它遵循后进先出原则。`panic`触发运行时错误,中断函数执行,直到遇到`recover`或程序结束。`recover`在`defer`中捕获`panic`,恢复程序执行。注意避免滥用`defer`影响性能,不应对可处理错误随意使用`panic`,且`recover`不能跨goroutine捕获panic。理解并恰当使用这些机制能提高代码健壮性和稳定性。
61 2
|
3月前
|
人工智能 Go 开发者
Golang语言异常机制解析:错误策略与优雅处理
Golang语言异常机制解析:错误策略与优雅处理
|
3月前
|
Go 索引
Golang深入浅出之-切片(Slices)入门:创建、操作与扩容机制
【4月更文挑战第20天】Go语言中的切片是动态数组,提供灵活的操作和自动扩容。本文介绍了切片的创建(通过`make()`、数组创建和切片字面量)、基本操作(索引访问、切片、赋值追加和遍历)以及扩容机制(首次和后续扩容策略)。此外,还强调了切片与底层数组的关系、切片越界问题、`append()`的使用以及理解切片的关键点,帮助提升Go编程效率和代码质量。
71 0
golang mutex一旋二饿三唤醒机制
golang mutex一旋二饿三唤醒机制
|
Linux Go C++
golang select 机制和超时
golang select 机制和超时
91 0