【读Go语言并发之道】第1,2章 并发概述以及CSP(顺序通信进程)

本文章收录于我的博客专栏读Go语言并发之道

前言:本文档是读《Go语言并发之道》一书之后的总结,按照章节进行记录。

目录

第一章 并发概述

第二章 对你的代码建模:顺序通信进程(CSP)


第一章 并发概述

  • 1.1 竞争条件

永远不要用time.Sleep来保证你程序运行的逻辑性,这不是一种优雅的方式,更不是一种正确的方式,还可能会给你的程序留下可能潜伏许久的难以调试的bug。

我们应该使用正确的协程间通信的方式来处理资源竞争的状况。

  • 1.2 原子性

当某些东西被定义为原子的,或具有原子性的。那在它的运行过程中,它是不可分割的或不可中断的,即使异常。

原子性的程序在并发环境中是安全的。(通常叫做并发安全/线程安全)

示例说明:我们必须在并发程序以非【原子操作】方式访问共享资源的时候,进行并发同步

data++ 不是原子操作,它可以细分为检索、修改、存储三个操作。

示例中,goroutine和主进程同时访问data,这不是安全的共享资源访问方式。

访问同一块内存的部分也叫做临界区。

  • 1.3 内存访问同步

我们使用一种非常见的方式来解决上个示例的同步问题。

问题:

  1. 以这种方式同步对内存的访问会带来相当大的性能问题,需要改善
  2. 没有解决逻辑正确性,示例中的goroutine和主进程谁先执行?
  3. 临界区应该有多大?
  4. 临界区是否能够频繁进入和退出?

解决这些问题是一种艺术,继续向下看。

 

  • 1.4 死锁、活锁和饥饿

死锁:指的是所有并发进程都在等待其他进程释放锁。这种情况下,若没有外界干预,永远无法恢复。

活锁:活锁指的是任务或者执行者没有被阻塞,由于某些条件没有满足,导致一直重复尝试—失败—尝试—失败的过程。处于活锁的实体是在不断的改变状态,活锁有可能自行解开

例如线程从队列中拿出一个任务来执行,如果任务执行失败,那么将任务重新加入队列,继续执行。假设任务总是执行失败,或者某种依赖的条件总是不满足,那么线程一直在繁忙却没有任何结果。

饥饿:任何情况下,并发进程都无法获得执行工作所需的所有资源。

饥饿更多指的是,有一个或多个贪婪的并发进程,它们争抢较多的共享资源,导致其他并发进程一直得不到资源,一直做无意义的等待。

这多是开发者设计不合理导致的。

 

第二章 对你的代码建模:顺序通信进程(CSP)

 

  • 2.1 并行与并发的区别

a. 大多数时候开发者们讨论的都应该是并发
b. 单核cpu机器上程序运行只有并发,无并行 
c. 单个cpu核心时间片通过快速切换执行不同程序来实现并发 
d. 多线程、协程都是并发模型

  • 2.2 Go语言的并发哲学

CSP是是go语言设计的重要组成部分。

编写并发代码有两种方式可选,一个是CSP,另一种就是内存访问同步;

这其实就是并发模型中的两种通信方式:

     1) 使用sync包就是通过共享内存来通信,这其实会降低并发程序的性能。

     2) sync与其他包中可以让你执行锁,创建资源池取代goroutine。

 

sync包文档中有如下描述:

在Go语言的FAQ中有:

如何选择选择合适的并发通信模型?

书中原话:使用最好描述,和最简单的那个方式。

书中推荐的决策方式:

Go语言的并发哲学总结:追求简洁,尽量使用channel,并且认为goroutine的使用是(几乎)没有成本的。(译文没有"几乎"二字,但个人认为添上更合理)

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
本书作者带你一步一步深入这些方法。你将理解 Go语言为何选定这些并发模型,这些模型又会带来什么问题,以及你如何组合利用这些模型的原语去解决问题。学习那些让你在独立且自信的编写与实现任何规模并发系统时所需要用到的技巧和工具。 理解Go语言如何解决并发难以编写正确这一根本问题。 学习并发与并行的关键性区别。 深入到Go语言的内存同步原语。 利用这些模式的原语编写可维护的并发代码。 将模式组合成为一系列的实践,使你能够编写大规模的分布式系统。 学习 goroutine 背后的复杂性,以及Go语言的运行时如何将所有东西连接在一起。 作者简介 · · · · · · Katherine Cox-Buday是一名计算机科学家,目前工作于 Simple online banking。她的业余爱好包括软件工程、创作、Go 语言(igo、baduk、weiquei) 以及音乐,这些都是她长期的追求,并且有着不同层面的贡献。 目录 · · · · · · 前言 1 第1 并发概述 9 摩尔定律,Web Scale和我们所陷入的混乱 10 为什么并发很难? 12 竞争条件 13 原子性 15 内存访问同步 17 死锁、活锁和饥饿 20 确定并发安全 28 面对复杂性的简单性 31 第2 对你的代码建模:通信顺序进程 33 并发与并行的区别 33 什么是CSP 37 如何帮助你 40 Go语言并发哲学 43 第3 Go语言并发组件 47 goroutine 47 sync包 58 WaitGroup 58 互斥锁和写锁 60 cond 64 once 69 池 71 channel 76 select 语句 92 GOMAXPROCS控制 97 小结 98 第4 Go语言并发模式 99 约束 99 for-select循环103 防止goroutine泄漏 104 or-channel 109 错误处理112 pipeline 116 构建pipeline的最佳实践 120 一些便利的生成器 126 扇入,扇出 132 or-done-channel 137 tee-channel 139 桥接channel模式 140 队列排队143 context包 151 小结 168 第5 大规模并发 169 异常传递169 超时和取消 178 心跳 184 复制请求197 速率限制199 治愈异常的goroutine 215 小结 222 第6 goroutine和Go语言运行时 223 工作窃取223 窃取任务还是续体 231 向开发人员展示所有这些信息 240 尾声 240 附录A 241

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值