阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Go中协程间通信的方式Sync.Cond

293次阅读
没有评论

共计 2755 个字符,预计需要花费 7 分钟才能阅读完成。

导读 在 Go 中协程间通信的方式有多种,最常用的是 channel。如果牵扯多个协程的通知,可以使用 sync.Cond。

Go 中协程间通信的方式 Sync.Cond

1. 程序中的通信方式

GO 语言中有句名言:“不要用共享内存来通信,而是使用通信来共享内存”。

编程语言中,通信方式分为进程间通信、线程间通信。

1. 进程间通信,常用方式:

  • 有名管道
  • 无名管道
  • 信号
  • 共享内存
  • 消息队列
  • 信号灯集
  • socket

2. 线程间通信,常用方式:

  • 信号量
  • 互斥锁
  • 条件变量

对于 Go 语言来说,Go 程序启动之后对外是一个进程,内部包含若干协程,协程相当于用户态轻量级线程,所以协程的通信方式大多可以使用线程间通信方式来完成。

协程间通信方式,官方推荐使用 channel,channel 在一对一的协程之间进行数据交换与通信十分便捷。但是,一对多的广播场景中,则显得有点无力,此时就需要 sync.Cond 来辅助。

2. 什么是广播?

举个例子,上高中时,宿管老师每天早晨需要叫醒学生们去上课。这个时候,有两种解决方法:①一个寝室一个寝室的把学生叫醒。②在宿舍楼安装个广播,到起床时间时,在广播上叫醒学生。显然,使用广播的方式效率更高。

编程中的广播可以理解为:多个操作流程依赖于一个操作流程完成后才能进行某种动作,这个被依赖的操作流程在唤醒所有依赖者时使用的一种通知方式。

在 Go 语言中,则可以使用 sync.Cond 来实现多个协程之间的广播通知功能。

3. sync.Cond

cond 是 sync 包下面的一种数据类型,相当于线程间通信的条件变量方式。

// Cond implements a condition variable, a rendezvous point 
// for goroutines waiting for or announcing the occurrence 
// of an event. 
// 
// Each Cond has an associated Locker L (often a *Mutex or *RWMutex), 
// which must be held when changing the condition and 
// when calling the Wait method. 
// 
// A Cond must not be copied after first use. 
type Cond struct { 
    noCopy noCopy  // 在第一次使用后不可复制, 使用 go vet 作为检测使用 
 
    // L is held while observing or changing the condition 
  // 根据需求初始化不同的锁,如 *Mutex 和 *RWMutex。注意是 指针类型 
    L Locker 
 
  // 具有头尾指针的链表。存储被阻塞的协程,通知时操作该链表中的协程 
    notify  notifyList 
    checker copyChecker  // 复制检查, 检查 cond 实例是否被复制 
}

该数据类型提供的方法有:

type Cond 
 
func NewCond(l Locker) *Cond 
func (c *Cond) Broadcast() // 通知所有协程,广播 
func (c *Cond) Signal()  // 通知一个协程 
func (c *Cond) Wait()  // 阻塞等待,直到被唤醒 

对应源码追溯

// Wait atomically unlocks c.L and suspends execution 
// of the calling goroutine. After later resuming execution, 
// Wait locks c.L before returning. Unlike in other systems, 
// Wait cannot return unless awoken by Broadcast or Signal. 
// 
// Because c.L is not locked when Wait first resumes, the caller 
// typically cannot assume that the condition is true when 
// Wait returns. Instead, the caller should Wait in a loop: 
//       
//      注意下面的写法是官方推荐的 
//    c.L.Lock() 
//    for !condition() {//        c.Wait() 
//    } 
//    ... make use of condition ... 
//    c.L.Unlock() 
// 
func (c *Cond) Wait() { 
    // 检查 c 是否是被复制的,如果是就 panic 
    c.checker.check() 
    // 获取等待队列的一个 ticket 数值,作为唤醒时的一个令牌凭证 
    t := runtime_notifyListAdd(&c.notify) 
    // 解锁 
    c.L.Unlock() 
   
    // 注意,上面的 ticket 数值会作为阻塞携程的一个标识 
    // 加入通知队列里面 
    // 到这里执行 gopark(),当前协程挂起,直到 signal 或 broadcast 发起通知 
    runtime_notifyListWait(&c.notify, t) 
   
    // 被唤醒之后,先获取锁 
    c.L.Lock()} 
 
// Signal wakes one goroutine waiting on c, if there is any. 
// 
// It is allowed but not required for the caller to hold c.L 
// during the call. 
func (c *Cond) Signal() {c.checker.check() 
    runtime_notifyListNotifyOne(&c.notify)  // 随机挑选一个进行通知,wait 阻塞解除 
} 
 
// Broadcast wakes all goroutines waiting on c. 
// 
// It is allowed but not required for the caller to hold c.L 
// during the call. 
func (c *Cond) Broadcast() {c.checker.check() 
    // 通知所有阻塞等待的协程 
    // 主要是唤醒 cond.notify 链表上的各个协程 
    runtime_notifyListNotifyAll(&c.notify) 
}

使用方法,代码示例:

var locker sync.Mutex 
var cond = sync.NewCond(&locker) 
 
// NewCond(l Locker) 里面定义的是一个接口, 拥有 lock 和 unlock 方法。// 看到 sync.Mutex 的方法,func (m *Mutex) Lock(), 可以看到是指针有这两个方法, 所以应该传递的是指针 
func main() { 
    // 启动多个协程 
    for i := 0; i 
总结

在 Go 中协程间通信的方式有多种,最常用的是 channel。如果牵扯多个协程的通知,可以使用 sync.Cond。

阿里云 2 核 2G 服务器 3M 带宽 61 元 1 年,有高配

腾讯云新客低至 82 元 / 年,老客户 99 元 / 年

代金券:在阿里云专用满减优惠券

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2024-07-25发表,共计2755字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

星哥玩云

星哥玩云
星哥玩云
分享互联网知识
用户数
4
文章数
19348
评论数
4
阅读量
7806477
文章搜索
热门文章
开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南

开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南

开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南 大家好,我是星哥。之前介绍了腾讯云的 Code...
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
云服务器部署服务器面板1Panel:小白轻松构建Web服务与面板加固指南

云服务器部署服务器面板1Panel:小白轻松构建Web服务与面板加固指南

云服务器部署服务器面板 1Panel:小白轻松构建 Web 服务与面板加固指南 哈喽,我是星哥,经常有人问我不...
我把用了20年的360安全卫士卸载了

我把用了20年的360安全卫士卸载了

我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
阿里云CDN
阿里云CDN-提高用户访问的响应速度和成功率
随机文章
星哥带你玩飞牛NAS硬件02:某鱼6张左右就可拿下5盘位的飞牛圣体NAS

星哥带你玩飞牛NAS硬件02:某鱼6张左右就可拿下5盘位的飞牛圣体NAS

星哥带你玩飞牛 NAS 硬件 02:某鱼 6 张左右就可拿下 5 盘位的飞牛圣体 NAS 前言 大家好,我是星...
星哥带你玩飞牛NAS硬件 01:捡垃圾的最爱双盘,暴风二期矿渣为何成不老神话?

星哥带你玩飞牛NAS硬件 01:捡垃圾的最爱双盘,暴风二期矿渣为何成不老神话?

星哥带你玩飞牛 NAS 硬件 01:捡垃圾的最爱双盘,暴风二期矿渣为何成不老神话? 前言 在选择 NAS 用预...
让微信公众号成为 AI 智能体:从内容沉淀到智能问答的一次升级

让微信公众号成为 AI 智能体:从内容沉淀到智能问答的一次升级

让微信公众号成为 AI 智能体:从内容沉淀到智能问答的一次升级 大家好,我是星哥,之前写了一篇文章 自己手撸一...
星哥带你玩飞牛NAS-13:自动追番、订阅下载 + 刮削,动漫党彻底解放双手!

星哥带你玩飞牛NAS-13:自动追番、订阅下载 + 刮削,动漫党彻底解放双手!

星哥带你玩飞牛 NAS-13:自动追番、订阅下载 + 刮削,动漫党彻底解放双手! 作为动漫爱好者,你是否还在为...
240 元左右!五盘位 NAS主机,7 代U硬解4K稳如狗,拓展性碾压同价位

240 元左右!五盘位 NAS主机,7 代U硬解4K稳如狗,拓展性碾压同价位

  240 元左右!五盘位 NAS 主机,7 代 U 硬解 4K 稳如狗,拓展性碾压同价位 在 NA...

免费图片视频管理工具让灵感库告别混乱

一言一句话
-「
手气不错
星哥带你玩飞牛 NAS-9:全能网盘搜索工具 13 种云盘一键搞定!

星哥带你玩飞牛 NAS-9:全能网盘搜索工具 13 种云盘一键搞定!

星哥带你玩飞牛 NAS-9:全能网盘搜索工具 13 种云盘一键搞定! 前言 作为 NAS 玩家,你是否总被这些...
安装并使用谷歌AI编程工具Antigravity(亲测有效)

安装并使用谷歌AI编程工具Antigravity(亲测有效)

  安装并使用谷歌 AI 编程工具 Antigravity(亲测有效) 引言 Antigravity...
每年0.99刀,拿下你的第一个顶级域名,详细注册使用

每年0.99刀,拿下你的第一个顶级域名,详细注册使用

每年 0.99 刀,拿下你的第一个顶级域名,详细注册使用 前言 作为长期折腾云服务、域名建站的老玩家,星哥一直...
Prometheus:监控系统的部署与指标收集

Prometheus:监控系统的部署与指标收集

Prometheus:监控系统的部署与指标收集 在云原生体系中,Prometheus 已成为最主流的监控与报警...
240 元左右!五盘位 NAS主机,7 代U硬解4K稳如狗,拓展性碾压同价位

240 元左右!五盘位 NAS主机,7 代U硬解4K稳如狗,拓展性碾压同价位

  240 元左右!五盘位 NAS 主机,7 代 U 硬解 4K 稳如狗,拓展性碾压同价位 在 NA...