golang 多协程的同步方法总结

之前用 go 写一个小工具的时候, 用到了多个协程之间的通信, 当时随手查了查, 结果查出来一大坨, 简单记录一下. golang中多个协程之间是如何进行通信及数据同步的嘞.

共享变量

一个最简单, 最容易想到的, 就是通过全局变量的方式, 多个协程读写同一个变量. 但对同一个变量的更改, 就不得不加锁了, 否则极易引发数据问题. 一般系统库都提供基本的锁, go 也提供了.

package mainimport ("fmt""sync""time"
)var num = 0
// 互斥锁
var mutex = sync.Mutex{}
// 读写锁
var rwMutex = sync.RWMutex{}func main() {for i := 0; i < 100; i++ {go incrNum()}time.Sleep(2)fmt.Println(num)
}func incrNum() {mutex.Lock()num = num + 1mutex.Unlock()
}

仅执行一次

当查询锁查到sync这个模块时, 发现它下面的对象并没有几个, 都是针对协程同步的各个方面给出的解决方案. 所以我就一个一个看文档试了试.

当你需要对环境, 连接池等等资源进行初始化时, 这种操作只需要执行一次, 这时候就需要它了. sync.Once对象可以保证仅执行一次. 和 init 方法有些类似, 不过 init 方法是在模块首次加载时执行, 而sync.Once是在首次调用时执行. (其实现就是一个计数器加一个互斥锁)

package mainimport ("fmt""sync""time"
)var num = 0
var once = sync.Once{}func main() {for i := 0; i < 100; i++ {go once.Do(incrNum)}time.Sleep(2)fmt.Println(num)
}func incrNum() {num = num + 1
}

等待其他协程处理

某个协程需要等第一阶段的所有协程处理完毕, 才能开始执行第二阶段. 这个时候, 等待其他协程就可以通过sync.WaitGroup 来实现. (当然, 也可以通过一个共享计数器变量来实现).

package mainimport ("fmt""sync"
)var waitGroup = sync.WaitGroup{}func main() {for i := 0; i < 100; i++ {go incrNum()}// 等待其他协程处理完毕(共享变量为0)waitGroup.Wait()fmt.Println("don")
}func incrNum() {// 增加需要等待的协程数量(共享变量+1)waitGroup.Add(1)// do something// 标记当前协程处理完成(共享变量-1)waitGroup.Done()
}

消息通知

多个协程启动时, 等待某个命令到来时执行命令, 唤醒等待协程. go 对此类操作也进行了处理, 感觉好贴心哦. 但是经过测试, 即使没有空闲的协程, 唤醒命令同样能够发出去, 所以需要注意一下.

package mainimport ("sync"
)var mutex = &sync.Mutex{}
var cond = sync.NewCond(mutex)func main() {for i := 0; i < 100; i++ {go incrNum()}// 发送命令给一个随机获得锁的协程cond.Signal()// 发送命令给所有获得锁的协程cond.Broadcast()
}func incrNum() {// 获取锁, 标识当前协程可以处理命令cond.L.Lock()// 可添加退出执行命令队列的条件for true {// 等待命令cond.Wait()// do something}// 释放锁, 标记命令处理完毕, 退出协程cond.L.Unlock()
}

多协程 map

普通的 map 在多协程操作时, 是不支持并发写入的. go贴心的给封装了支持并发写入的map. 同时也提供了针对map的基本操作.

package mainimport ("fmt""sync""time"
)var m = sync.Map{}func main() {for i := 0; i < 100; i++ {go func() {m.Store("1", 1)}()}time.Sleep(time.Second * 2)// 遍历 mapm.Range(func(key, value interface{}) bool {// 返回 false 结束遍历return true})// 读取变量, 若不存在则设置m.LoadOrStore("1", 3)// 删除 keym.Delete("1")// 读取变量load, _ := m.Load("1")fmt.Println(load)
}

多协程对象池

对于数据库连接池应该并不陌生. 而sync.Pool对象是go封装的协程安全的对象池. 对象池的使用十分简单, 存/取

package mainimport ("sync"
)var p = sync.Pool{// 当池子中没有对象了, 用于创建新对象New: func() interface {}{return "3"},
}func main() {// 从池子中获取一个对象r := p.Get()// 用完后将对象放回池子中p.Put(r)
}

sync 简单总结

针对go系统的sync模块, 提供的基础功能如下:

  1. 互斥锁 Mutex
  2. 读写锁 RWMutex
  3. 函数单次执行 Once
  4. 协程执行等待 WaitGroup
  5. 协程消息通知 Cond
  6. 多协程 map Map
  7. 多协程对象池 Pool

几个都简单试过之后, 发现sync模块针对常用的几个多协程工具进行了封装, 想来可以基本满足日常使用了.

终极通信-channel

channel是一个协程安全的通信管道, 简单理解为数据从一侧放入, 从另一侧拿出. 这玩意感觉能玩出花来, 还不太理解, 留到国庆研究.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/508400.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

golang chan 探究

前言 之前在看golang多线程通信的时候, 看到了go 的管道. 当时就觉得这玩意很神奇, 因为之前接触过的不管是php, java, Python, js, c等等, 都没有这玩意, 第一次见面, 难免勾起我的好奇心. 所以就想着看一看它具体是什么东西. 很明显, 管道是go实现在语言层面的功能, 所以我以…

计算机网络-信道复用技术

还记得计算机网络中的信道复用技术么? 来来来, 一起复习一下. why 问: 什么是信道复用. 在回答这个问题之前先看这样一个场景: 其中u1 u2是两个用户, 如果这两个用户之间连通的信道在他们使用过程中, 被他们完全占用了, 其他人就只能等着了. 那有人说了, 那就多架设信道不就…

IP 数据报首部分析

来来来, 爷们. 不是一直说纸上得来终觉浅么. 今咱就抓个数据报具体看一看真实网络中的 IP 报首部. 操作方法很简单, 使用wireshark进行抓包. 抓包后随便找个包看一下就行, 毕竟所有通信的包都需要经过网络层.(同时, wireshark会对协议的相关信息给出标识, 更方便我们查看) 其中…

git 子模块在项目中的使用

在公司的项目中, 经常会遇到一些公共的内容, 多个项目中间通用的, 不可能每次都将整个代码复制一遍, 遇到这种情况有很多不同的解决方案, 一般来说, 项目是通过 git 来管理的, 巧了, git 也同样支持子模块. 创建子模块 git submodule add gitgitee.com:hujingnb/submodule_so…

Hello IPv6

前言 IPv4 大家都不陌生, 就是我们平常使用的32位网络地址. 但是, 因为可能在其发展初期, 并没有考虑的十分全面, 故而其存在一些缺陷: 32位二进制仅支持约43亿个设备, 还不到全球的人口数量. (故而现在依赖于各种局域网转换技术, 比如 NAT. 否则地址早就不够用了. 但是 NAT …

GO 内存对齐

前言 之前遇到过这样一个情况(发现问题的结构体并不长这样, 不过为了引出问题, 改了一下): type Test struct { b bool i3 int32 i8 int8 i64 int64 by byte } func main() { t : Test{} fmt.Printf("%d", unsafe.Sizeof(t)) } 创建一个结构体, 查看一下其内存占用.…

HBase 命令行

hbase是一款分布式数据库. 其对数据的索引只通过row key进行. 在存储数据的时候, 通过row key的排序进行存储. 在面对一个新的数据库时, 深究其原理并不知一个明智的选择, 正如开车一般, 大多数人都是先学会开车, 然后在开车的过程中车子出故障了, 再慢慢学着去修理. 不管怎么说…

《论可计算数及其在判定上的应用》简单理解

刚刚拜读了一本书, 《图灵的秘密》. 该书介绍了图灵的论文《论可计算数及其在判定上的应用》, 其指出: 一个拥有铅笔, 纸和一串明确指令的人类计算者, 可以被看做是一种图灵机. 那么图灵机是什么呢? 是图灵为了描述可计算数而引出的一个虚构的可以做一些简单操作的计算机器. 尽…

PHP为什么empty可以访问不存在的索引

开始之前, 先抛出问题: $arr []; echo empty: , PHP_EOL; var_dump(empty($arr[1])); echo is_array: , PHP_EOL; var_dump(is_array($arr[1]));这段代码的运行结果: 你是否和我有过同样的疑问? 同样是函数, 为什么empty访问不存在的索引就不会报错呢? 按理说哈, 函数调用的…

浮点数运算丢失精度

今天碰到了这样一个情况, 使我又去翻阅了原来课本, 在Pthon中如果输入下面这段程序: print(sys.float_info.max - 1.0) print(sys.float_info.max)结果如下: 结果发现, 这数字根本没有变化. 本来这没什么, 看这数字, 10的308次方, 也就是说, 减去的1是在308位之后了, 这里没有…

变量的作用域

起因 最近闲来无事, 在 Python 官网上看到了2.0版本, 是2001年的. 打算装起来体验一下最初发布的版本, 但是发现只有 Windows 版本, 所以我就装了个 Windows10的虚拟机, 就在我打算安装的时候, 发现: 这激起了我的好胜欲, 于是我就依次安装了Windows 8, Windows 7, Windows XP…

PHP8的注解

PHP8.0增加了注解的支持, 虽然 PHP的注解没用过, 但是咱用过JAVA的注解呀. 注解这玩意怎么用? 简单说就下面几步: 定义注解类使用注解提取注解 到了PHP中, 也基本上换汤不换药. 使用 定义注解类 #[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_FUNCTION)] cl…

目的论浅谈

一些心理学主张, 我们的现在乃至未来, 都是由过去所经历的事情所决定的, 这种思想被称为 “原因论”, 同时也符合佛家的思想. 而相对的另一种解释就是 “目的论”. 举个例子, 如果你在饭店吃饭, 被服务员不小心把汤打翻了, 泼了你一身. 此时, 你愤怒不已, 站起身来破口大骂, 此…

HBase 数据存储结构

在HBase中, 从逻辑上来讲数据大概就长这样: 单从图中的逻辑模型来看, HBase 和 MySQL 的区别就是: 将不同的列归属与同一个列族下支持多版本数据 这看着感觉也没有那么太大的区别呀, 它解决了 MySQL 的那些问题呢? 每一个新事物的出现, 都是为了解决原本存在的问题. 对写入…

HBase 文件合并

HBase在存储时, 使用了LSM树来进行数据存储, 会定期将文件进行合并, 以提升数据的查询效率, LSM树都是这么处理的. 那么到这里就有一个问题了, HBase在进行文件合并的时候, 势必会占用大量 IO, 难道不会对正常的业务产生影响么? 抱着这个疑问, 我去找了找HBase文件合并的方式.…

spark计算操作整理

spark 的计算流程大概如图: 其中, 通过多次处理, 生成多个中间数据, 最后对结果进行操作获得数据. 本文不涉及任何原理, 仅总结spark在处理的时候支持的所有操作, 方便后面使用的时候, 可以参照本文进行数据的处理. 以下函数整理, 基与Python中RDD对象. 数据的转换操作 数据…

软件工程模型

你在工作中, 软件的开发流程是怎样的? 你是否想过, 除了你当前使用的流程, 还存在其他怎样的流程? 现在的流程有哪些问题, 又能够如何解决? 别说, 前辈们已经给出了一些项目流程的模型, 既软件工程. 可以简单了解一下, 带动一下我这生了锈的脑子. 在很久以前, 一个软件的从…

关于对接需求的思考

产品说想要一个登录注册的功能, 你一想, 好说, 不就是用户名密码嘛, 然后开发完成 产品看到成果后: 我要的是手机验证码登录结果写好的功能基本废了 产品又想要一个登录注册的功能, 这回你学乖了, 确认了一下, 是手机验证码登录, 没问题, 然后开发完成 产品拿到成果: 怎么没有验…

路径.git下的文件

用了这么久的git, 可以毫不谦虚地说对git是一无所知. 每天用来用去的就是commit, add, merge 等几个有限的命令, 这不符合我这刨根问底的性格啊. 不行, 得研究研究, 从哪里下手呢? 别的咱先不说, 所有 git 项目都有这么一个文件夹.git, 不如就从它入手 ? 那咱就看看这个文件夹…

git 操作二进制文件

平常用git进行项目管理已经稀松平常了, 今天咱来点不一样的. 平常管理的都是普通的文本文件, 如果是二进制文件, git能够处理么? 比如word文档. 测试一下. 新建一个项目, 在其中创建test1.docx, test2.txt两个空文件并提交. 之后编辑文件并添加标题, git diff看一下效果: 效…