go是通过协程goroutine来实现并发的,goroutine创建短小轻量级的开销让人确实着迷,它屏蔽了OS层面多线程的操作,如果写过Java代码我们知道并发程序的设计和要考虑到的问题是多么让人头疼了,当然并不是说Java不好,而且Java现在通过某种手段也能实现类似goroutine的功能,语言本身不重要,重要的是它实用的场景,关于Java和Go的长处短处这里也不展开了,但是可以知道一点只要有并发必然会涉及到资源的竞争,那么goroutine是如何避免这个问题的呢?当然阅读本篇文章假设我们已经有了go的语言基础,可以看易佰教程迅速入门https://www.yiibai.com/go/

我们先简单的看一个并发资源争夺的例子:

package main
import ("fmt""runtime""sync"
)
var (count int32wg    sync.WaitGroup //WaitGroup总共有三个方法:Add(delta int),Done(),Wait(),简单的说一下这三个方法的作用:Add:添加或者减少等待goroutine的数量,Done:相当于Add(-1),Wait:执行阻塞,直到所有的WaitGrou数量变成0
)func sCount() {defer wg.Done()for i := 0; i < 2; i++ {value := countruntime.Gosched()//把cpu让出来,让另一个goroutine跑value++count = value}
}func main() {wg.Add(2)go sCount()go sCount()wg.Wait()fmt.Println(count)
}

我们可以多运行几次这个程序,会发现结果可能是2,也可以是3,也可能是4。因为共享资源count变量没有任何同步保护,所以两个goroutine都会对其进行读写,会导致对已经计算好的结果覆盖,以至于产生错误结果,这里我们演示一种可能,两个goroutine我们暂时称之为g1和g2。

g1读取到count为0。
然后g1暂停了,切换到g2运行,g2读取到count也为0。
g2暂停,切换到g1,g1对count+1,count变为1。
g1暂停,切换到g2,g2刚刚已经获取到值0,对其+1,最后赋值给count还是1
有没有注意到,刚刚g1对count+1的结果被g2给覆盖了,两个goroutine都+1还是1
不再继续演示下去了,到这里结果已经错了,两个goroutine相互覆盖结果。我们这里的runtime.Gosched()是让当前goroutine暂停的意思,退回执行队列,让其他等待的goroutine运行,目的是让我们演示资源竞争的结果更明显。注意,这里还会牵涉到CPU问题,多核会并行,那么资源竞争的效果更明显。

所以我们对于同一个资源的读写必须是原子化的,也就是说,同一时间只能有一个goroutine对共享资源进行读写操作。

那么怎么解决这个问题呢?go语言提供了atomic包和sync包里的一些函数对共享资源同步枷锁,这两种的包的使用原理都差不多,但atomic支持的数据类型有限,使用sync包里提供了一种互斥型的锁可以更灵活的控制互斥区:

package main
import ("fmt""runtime""sync"
)
var (count int32wg    sync.WaitGroupmutex sync.Mutex
)func sCount() {defer wg.Done()for i := 0; i < 2; i++ {mutex.Lock()value := countruntime.Gosched()value++count = valuemutex.Unlock()}
}
func main() {wg.Add(2)go sCount()go sCount()wg.Wait()fmt.Println(count)
}

实例中,新声明了一个互斥锁mutex sync.Mutex,这个互斥锁有两个方法,一个是mutex.Lock(),一个是mutex.Unlock(),这两个之间的区域就是临界区,临界区的代码是安全的。

示例中我们先调用mutex.Lock()对有竞争资源的代码加锁,这样当一个goroutine进入这个区域的时候,其他goroutine就进不来了,只能等待,一直到调用mutex.Unlock() 释放这个锁为止。

这种方式比较灵活,可以让代码编写者任意定义需要保护的代码范围,也就是临界区。除了原子函数和互斥锁,Go还为我们提供了更容易在多个goroutine同步的功能,这就是通道chan,在通道里我们才能感受到go语言的并发之美,感受到go语言为什么奉行“通过通信来共享内存”的理念!在下一章我们将学习通道chan,感受go的并发之美!!!

golang并发资源的竞争相关推荐

  1. ​Golang 并发编程指南

    分享 Golang 并发基础库,扩展以及三方库的一些常见问题.使用介绍和技巧,以及对一些并发库的选择和优化探讨. go 原生/扩展库 提倡的原则 不要通过共享内存进行通信;相反,通过通信来共享内存. ...

  2. Golang并发模型:轻松入门协程池

    goroutine是非常轻量的,不会暂用太多资源,基本上有多少任务,我们可以开多少goroutine去处理.但有时候,我们还是想控制一下. 比如,我们有A.B两类工作,不想把太多资源花费在B类务上,而 ...

  3. golang 并发demo 写入 redis

    原文链接:golang 并发demo 写入 redis 源代码: package mainimport ("fmt""runtime""strconv ...

  4. Golang并发模型:合理退出并发协程

    goroutine作为Golang并发的核心,我们不仅要关注它们的创建和管理,当然还要关注如何合理的退出这些协程,不(合理)退出不然可能会造成阻塞.panic.程序行为异常.数据结果不正确等问题.这篇 ...

  5. 4种Golang并发操作中常见的死锁情形

    摘要:什么是死锁,在Go的协程里面死锁通常就是永久阻塞了,你拿着我的东西,要我先给你然后再给我,我拿着你的东西又让你先给我,不然就不给你.我俩都这么想,这事就解决不了了. 本文分享自华为云社区< ...

  6. Golang并发:再也不愁选channel还是选锁

    周末又到了,为大家准备了一份实用干货:如何使用channel和Mutex解决并发问题,利用周末的好时光,配上音乐,思考一下吧?. 来,问自己个问题:面对并发问题,是用channel解决,还是用Mute ...

  7. golang并发编程之Ticker

    golang并发编程之Ticker Timer只执行一次,Ticker可以周期的执行 icker是一个定时触发的计时器 它会以一个间隔(interval)往channel发送一个事件(当前时间) 而c ...

  8. Golang并发模型:轻松入门流水线FAN模式

    前一篇文章<Golang并发模型:轻松入门流水线模型>,介绍了流水线模型的概念,这篇文章是流水线模型进阶,介绍FAN-IN和FAN-OUT,FAN模式可以让我们的流水线模型更好的利用Gol ...

  9. Golang并发实现Nginx日志分析与监控(2)——完整代码

    本代码实现了从Nginx日志access.log中读取信息,并用正则解析,最后将requestTime从端口暴露,以便让prometheus抓取.使用Golang并发实现. package maini ...

最新文章

  1. java为什么序列化不一致_java – 为什么Jackson多态序列化在列表中不起作用?
  2. 安装meme_通过构建Meme生成器学习React
  3. 解决项目中.a文件的冲突
  4. CSS揭秘之《背景图案》
  5. nyoj 947 Max Xor(字典树)
  6. python小结_python简单小结
  7. BZOJ1015 JSOI2008 星球大战starwars 并查集
  8. crossin的编程教室python入门_简单三步,用 Python 发邮件
  9. vs下使用qt设置应用程序的图标
  10. CVPR2021系列(一)—— 语义图像抠图
  11. wos 文献被引_CiteSpace与Histcite在文献引用上的区别
  12. 2021 ICPC Asia Jinan Regional Contest-J Determinant(取模高斯消元)
  13. qt qstandarditemmodel rowcount获取行数不正确_MIL+QT实践教程十
  14. 深度学习2.0-44.对抗生成网络-GAN
  15. 微型计算机原理与接口技术第二版答案邹逢兴,清华大学出版社-图书详情-《微型计算机原理与接口技术教学辅导(第2版)》...
  16. Android 游戏引擎libgdx之Box2D Hello Box2D
  17. Spring Security,没有看起来那么复杂(附源码)
  18. 电报注册_更秘密的电报
  19. 零基础也能看懂的五大网络安全技术,学网络真的可以很简单
  20. openGauss之gsql工具的使用

热门文章

  1. mysql 漏洞 wa_[漏洞案例]thinkcmf 2.x从sql注入到getshell实战
  2. Instagram API平台文档
  3. SpringBoot整合Redis实现优惠券秒杀服务(笔记+优化思路版)
  4. 私有云 虚拟服务器 区别,虚拟主机介绍 虚拟主机是不是私有云
  5. 7-6 吃鱼还是吃肉 (20 分)
  6. 祭奠一位我无比亲爱的亲人的离去
  7. 安卓内存监控工具,2021年Android面试心得,系列教学
  8. 开源搜索引擎评估:lucene sphinx elasticsearch
  9. HAKE笔记:Learning Hierarchy-Aware Knowledge Graph Embeddings for Link Prediction
  10. mtk-disp开篇:名词扫盲