go学习笔记-goroutine竞争状态

如果两个或者多个goroutine在没有相互同步状态的情况下同时访问某个资源,并且同时对这个资源进行读写的时候,对于这个资源就处于相互竞争状态(race candition)。下面来看一个相互竞争的例子。
var number int
var wait sync.WaitGroup
func main()  {
    wait.Add(2)
    go updateNumber(20000)//加20000
    go updateNumber(30000)//加30000
    wait.Wait()
    fmt.Println(number)
}
func updateNumber(addNumber int)  {
    for i:=0;i<addNumber ;i++  {
        number ++
    }
    wait.Done()
}

上面这个例子,我们期望得到的值应该是500000,但是我们最后得到值,并不是500000,而且每次得到的结果是不一样的。这是为什么呢?因为在两个goroutine中没有同步number的当前值,就会存在两个goroutinenumber值重复赋值的问题,造成值覆盖。这样就得不到我们预期的结果。

上面的例子我们可以看到,如果没有对竞争的资源进行有效的管理以及合理的处理,并发程序就会变的很复杂,并且会产生一些意想不到的错误。所以我们需要对竞争资源进行管理来避免这些问题。Go中提供一些传统的方式来处理这类问题
原子函数 atomic
原子函数能够以很底层的加锁机制来同步访问整型变量和指针,我们可以使用原子函数来处理竞争问题。
var number int32
var wait sync.WaitGroup
func main()  {
    wait.Add(2)
    go updateNumber(20000)
    go updateNumber(30000)
    wait.Wait()
    fmt.Println(number)
}
func updateNumber(addNumber int)  {
    defer wait.Done()
    for i:=0;i<addNumber ;i++  {
        atomic.AddInt32(&number,1)
    }

}

这里我们使用了atmoic包的AddInt32 函数。这个函数会同步整型值的加法,
方法是强制同一时刻只能有一个goroutine 运行并完成这个加法操作。当goroutine试图去调用任
何原子函数时,这些goroutine 都会自动根据所引用的变量做同步处理。atmoic包中还提供了LoadStore方法,对资源进行安全的读与写。

互斥锁 mutex
另一种方式是创建一个互斥锁来锁住一个区域,来保证同一个资源不会被同时修改或者使用。保证当前只有一个goroutine在执行当前区域的代码。
var (
    number int32
    wait sync.WaitGroup
    mutex sync.Mutex
    )
func main()  {
    wait.Add(2)
    go updateNumber(20000)
    go updateNumber(30000)
    wait.Wait()
    fmt.Println(number)
}
func updateNumber(addNumber int)  {
    defer wait.Done()
    for i:=0;i<addNumber ;i++  {
        mutex.Lock() // 加锁
        number++;
        mutex.Unlock() //释放锁
    }
}

上面的代码片段,在Number改变的前后对当前区域加锁,最后也能得到我们的目的,但是这样的会话,每次在number变更的时候,都会创建锁与释放锁,会对性能产生很大的影响。其实我们可以在for循环区域来加锁。

func updateNumber(addNumber int)  {
    defer wait.Done()
    mutex.Lock() // 加锁
    for i:=0;i<addNumber ;i++  {
        number++;
    }
    mutex.Unlock() //释放锁
}

后面这种形式的效率明显是要比第一种高很多的。所以我们程序有使用互斥锁的话,需要考虑加锁的粒度问题。

虽然上面上面两种方式也可以解决竞争问题,但是在go中有一种更好的方式来解决这个问题,那就是goroutine的好兄弟channel。由于channel的内容比较多,所以我将单独写一个笔记来记录这方面的问题。期待下一篇的更新

期待一起交流

file

Image placeholder
旧梦发癫
未设置
  73人点赞

没有讨论,发表一下自己的看法吧

推荐文章
谷歌云重磅推出混合云平台Anthos,兼容竞争对手云服务 | Google Cloud Next’19

大数据文摘出品作者:蒋宝尚、周素云当地时间4月9日,谷歌云年度盛会GoogleCloud Next’19在旧金山的Moscone召开。在会上,谷歌云的新任CEO,曾经的甲骨文二号人物ThomasKur

从词袋到transfomer,梳理十年Kaggle竞赛,看自然语言处理的变迁史

大数据文摘出品来源:medium编译:LYLM、胡笳自2010年创办以来,Kaggle作为著名的数据科学竞赛平台,一直都是机器学习领域发展趋势的风向标,许多重大突破都在该平台发生,数以千计的从业人员参

2019机器学习框架之争:与Tensorflow竞争白热化,进击的PyTorch赢在哪里?

大数据文摘出品来源:thegradient编译:张大笔茹、曹培信、刘俊寰、牛婉扬、Andy2019年,机器学习框架之争进入了新阶段:PyTorch与TensorFlow成为最后两大玩家,PyTorch

AI 计算竞争升级,参访平安科技背后的硬实力

平安科技的四块科技版图,分别是云、认知、区块链和人工智能。所有的AI公司在AI领域中最核心的壁垒不是技术,因为技术都是人创造的,打磨团队就可以。核心的壁垒应该时间、业务和场景。智能科技的涌现、大数据

IBM收购红帽案已完成交易,混合云竞争格局变得更微妙!

自从去年年底IBM放出消息要收购红帽后,这个开源软件领域的最大并购案,就一直牵动着无数人的神经。而现在,这笔价值340亿美元的交易,终于成为既定事实。本周二,IBM和红帽共同宣布,已通过现金的形式正式

对话OceanBase资深总监韩鸿源:数据库是技术能力,云是使用方式,两者不应是竞争关系

5月10日,在第十届中国数据库技术大会(DTCC2019)上,蚂蚁金服的金融级分布式关系数据库OceanBase2.0,在经过200名数据库领域三年以上的从业者投票和专业评委的评选下,高分荣获了“年度

ERP云端相竞,QAD “中国云”的差异化竞争

提起海外知名ERP厂商可能很多人会想到SAP、Oracle,但在制造业尤其是汽车领域大家对QAD也许会更为熟悉。专注于制造业40年的QAD今年也迎来了在华的20岁生日,在6月13日举行的QAD2019

jQuery 学习笔记

jQuery中的dom追加操作方法(主动/被动、前面/后面、里面/外面): append:主动/后面/里面 appendTo:被动/后面/里面 prepend:主动/前面/里面 prependTo:被

流畅的python学习笔记-第4章

第4章文本和字节序列[toc]编码和解码markdom可以插入emoji表情包其中作为前缀,x1f54为对应表情的unicode编码🥺emoji 把码位转换成字节序列的过程是编码;把字节序列转换成码位

流畅的python学习笔记-第5章

第5章函数[toc]函数在python中一切都可以视作为对象,包括函数deffunction_try(): '''itisfuncitontrydoc''' print('function_tryd

软件工程学习笔记(一):软件工程

1计算机软件1.1软件计算机软件是指计算机系统中的程序以及文档,程序是计算任务处理对象和处理规则的描述.1.2软件特点 一种逻辑实体. 维护工作量大. 维护软件过程中会引入副作用. 1.3软件分类1.

Redis学习笔记2—缓存、集群、一致性等

缓存淘汰策略为了保证高性能,缓存都保存在内存中,当内存满了之后,需要通过适当的策略淘汰老数据,以便腾出空间存储新数据。数据的淘汰策略,典型的包括FIFO(先进先出,淘汰最老数据),LRU(淘汰最近最少

Go语言高级编程_3.8 例子:Goroutine ID

3.8例子:GoroutineID 在操作系统中,每个进程都会有一个唯一的进程编号,每个线程也有自己唯一的线程编号。同样在Go语言中,每个Goroutine也有自己唯一的Go程编号,这个编号在pani

goroutine

goroutine本质上是大号版的异步执行句柄,比之nodejs中的单线程事件循环处理器。之所以在使用goroutine,感觉不到异步,在于golang已经封装了各种异步io操作,运行时一旦发现异步

大话 goroutine

goroutine本质上是大号版的异步执行句柄,比之nodejs中的单线程事件循环处理器。之所以在使用goroutine,感觉不到异步,在于golang已经封装了各种异步io操作,运行时一旦发现异步

Go语言高级编程_5.2 router 请求路由

5.2router请求路由 在常见的Web框架中,router是必备的组件。Go语言圈子里router也时常被称为http的multiplexer。在上一节中我们通过对Burrow代码的简单学习,已经

怎么安装react-router

怎么安装react-router安装命令:npminstallreact-routerreact-router路由提供了一些router的核心api,包括Router,Route,Switch等,但是

最新 React Router 全面整理

Reactrouter已经到了V5版本,增加了基于ReactHooks的一些API,比如useParams、useHistory等等,让我们可以在组件中不接受routeprops就可以拿到路由信息{m

学习猿地PHP第一关课堂笔记

什么是PHP? 绰号:拍黄片 服务器端的脚本语言 超文本预处理器 注意:所有的PHP文件不能直接双击打开,必须经过服务器打开,不经过服务器访问不到。 创建PHP文件 php文件后缀名是.php

一个多业务、多状态、多操作的交易链路?闲鱼架构这样演进

前言双十一刚刚结束,成交额2684亿震惊全世界,每秒订单峰值达54.4W笔。在闲鱼2000万DAU,交易数额同样增长迅速的今天,我们如何保障交易链路的稳定与快速支撑业务?这篇文章从客户端开发的角度,介

职责驱动设计及状态模式的融会贯通

一、需求针对某通信产品,我们需要开发一个版本升级管理系统。该系统通过Java开发后台管理,由Telnet发起向前端基站设备的命令,以获取基站设备的版本信息,并在后台比较与当前最新版本的差异,以确定执行

【PHP学习】PHP入门学习 之 常量

PHP常量是一个简单值的标识符(名字)。如同其名称所暗示的,在脚本执行期间该值不能改变(除了所谓的魔术常量,它们其实不是常量)。PHP常量默认为大小写敏感。传统上常量标识符总是大写的。 PHP常量名

Go语言高级编程_5.7 layout 常见大型 Web 项目分层

5.7layout常见大型Web项目分层 流行的Web框架大多数是MVC框架,MVC这个概念最早由TrygveReenskaug在1978年提出,为了能够对GUI类型的应用进行方便扩展,将程序划分为:

笨办法学 Linux 学习处理文件,`pwd`,`ls`,`cp`,`mv`,`rm`,`touch`

Bash:处理文件,pwd,ls,cp,mv,rm,touch 在Linux中,一切都是文件。但是什么是文件?现在完全可以说,它是一个包含一些信息的对象。它通常定义如下: 计算机文件是用于存储信息的

Kubernetes 基础信息:什么是 Kubernetes?

简介 Kubernetes(常简称为K8s,在希腊语意为“舵手”或“驾驶员”)是用于自动部署、扩展和管理容器化(containerized)应用程序的开源系统。 由JoeBeda、BrendanBur