Bruce Blog Bruce Blog
首页
  • CentOS
  • Ubuntu-Debian
  • 系统网络
  • 系统辅助工具
  • MySQL
  • Redis
  • Mongodb
  • Docker基础
  • Container基础
  • Kubernetes

    • Kubernetes基础
    • Kubernetes辅助
  • Container-Network
  • Jenkins
  • Gitlab
  • ArgoCD
  • Ansible
  • Terraform
  • AWS
  • MQ
  • NGINX
  • JumpServer
  • 基础
  • 函数模块
  • 框架
  • 基础

    • Golang环境
    • 语法
    • 数据类型与运算符
    • 分支语句
    • 循环语句
    • 数组
    • 切片
    • Map
    • String
    • 函数
    • 包的管理
    • 指针
    • 结构体
    • Go语言中的OOP
    • 方法和接口
    • 错误处理
  • Go进阶

    • Go进阶
  • Go框架

    • Go框架
  • Golang辅助

    • Golang辅助
  • CSS
  • HTML
  • JavaScript
  • 前端辅助
  • 常用命令
  • 性能监控工具
  • Windows下Docker使用
  • 日常学习
  • 其他导航

Bruce Tao

运维界的该溜子
首页
  • CentOS
  • Ubuntu-Debian
  • 系统网络
  • 系统辅助工具
  • MySQL
  • Redis
  • Mongodb
  • Docker基础
  • Container基础
  • Kubernetes

    • Kubernetes基础
    • Kubernetes辅助
  • Container-Network
  • Jenkins
  • Gitlab
  • ArgoCD
  • Ansible
  • Terraform
  • AWS
  • MQ
  • NGINX
  • JumpServer
  • 基础
  • 函数模块
  • 框架
  • 基础

    • Golang环境
    • 语法
    • 数据类型与运算符
    • 分支语句
    • 循环语句
    • 数组
    • 切片
    • Map
    • String
    • 函数
    • 包的管理
    • 指针
    • 结构体
    • Go语言中的OOP
    • 方法和接口
    • 错误处理
  • Go进阶

    • Go进阶
  • Go框架

    • Go框架
  • Golang辅助

    • Golang辅助
  • CSS
  • HTML
  • JavaScript
  • 前端辅助
  • 常用命令
  • 性能监控工具
  • Windows下Docker使用
  • 日常学习
  • 其他导航
  • 基础

  • Go进阶

    • Go进阶
    • File操作
    • IO操作
    • 文件复制
    • 断点续传
    • bufio包
    • ioutil包
    • 遍历目录
    • 并发性Concurrency概念
    • Goroutine初识
    • Goroutine并发模型
    • Runtime包
    • 临界资源安全问题
    • sync包WaitGroup
    • 互斥锁
    • 读写锁
    • Channel通道
    • 关闭通道和通道上范围循环
    • 缓冲通道
    • 定向通道
    • time包中的通道相关函数
    • select语句
    • CSP并发模型
      • Go语言反射(一)
      • Go语言反射(二)
    • Go框架

    • Golang辅助

    • Golang
    • Go进阶
    Bruce
    2022-12-03
    目录

    CSP并发模型

    # Go语言的CSP模型

    go语言的最大两大亮点,一个是goroutine,一个就是chan了.二者合体的典型应用CSP,基本就是并行开发神器,简化了并行程序的开发难度.

    # 一、CSP是什么

    CSP是Communicating Sequential Process的简称,中文可以叫做通信顺序进程,是一种并发编程模型,是一个很强大的并发数据模型,是上世纪七十年代提出的,用于描述两个独立的并发实体通过共享的通讯channel(管道)进行通信的并发模型.相对于Actor模型,CSP中channel是第一类对象,它不关注发送消息的实体,而关注与发送消息时使用的channel.

    严格来说,CSP是一门形式语言(类似于image-20221125135958550calculus),用于描述并发系统中的互动模式,也因此称为一众面向并发的编程语言的理论源头,并衍生了Occam/Limbo/Golang...

    而具体到编程语言,如Golang,其实只用到了CSP的很小一部分,即理论中的Proccess/Channel(对应到语言中的goroutine/channel): 这两个并发原语之间没有从属关系,Process可以订阅任意个Channel,Channel也并不关心是哪个Process在利用它进行通信;Process围绕Channel进行读写,形成一套有序阻塞和可预测的并发模型.

    # 二、Golang CSP

    与主流语言通过共享内存来进行并发控制方式不同,Go语言采用了CSP模式,这是一种用于描述两个独立的并发实体通过共享的通讯Channel(管道)进行通信的并发模型.

    Golang就是借用CSP模型的一些概念为之前实现并发进行理论支持,其实从实际上出发,go语言并没有,完全实现了CSP模型的所有理论,仅仅是借用了process和channel这两个概念.process是在go语言上的表现就是goroutine是实际并发执行的实体,每个实体之间是通过channel通讯来实现数据共享.

    Go语言的CSP模型是由协程Goroutine与通道Channel实现:

    • Go协程goroutine: 是一种轻量线程,它不是操作系统的线程,而是将一个操作系统线程分段使用,通过调度器实现协作式调度.是一种绿色线程,微线程,它于Coroutine协程也有区别,能够在发现阻塞后启动新的微线程.
    • 通道channel: 类似Unix的Pipe,用于协程之间通讯和同步.协程之前虽然解耦,但是他们和Channel有着耦合.

    # 三、Channel

    Goroutine和channel是Go语言并发编程的两个基石.Goroutine用于执行并发任务,channel用于goroutine之间的同步、通道.

    Channel在goroutine间架起了一条管道,在管道里传输数据,实现goroutine间的通信;由于它是线程安全的,所以用起来非常方便;channel还提供"先进先出"的特性;它还能影响goroutine的阻塞和唤醒.

    不要通过共享内存来通信,而要通过通信来实现内存共享.

    Do not communicate by sharing memory,instead,share memory by communicating.

    这就是Go的并发哲学,它依赖CSP模型,基于channel实现.

    # channel实现CSP

    Channel是Go语言中一个非常重要的类型,是Go里的第一对象.通过channel,Go实现了通过通信来实现内存共享.Channel是在多个goroutine之间传递数据和同步的重要手段.

    使用原子函数、读写锁可以保证资源的共享访问安全,但使用channel更优雅.

    channel字面意义是"通道",类似于Linux中的管道.说明channel的语法如下:

    chan T //声明一个双向通道
    chan<-  //声明一个只能用于发送的通道
    <-chan T //声明一个只能用于接收的通道
    
    1
    2
    3

    单向通道的声明,用<-来表示,它指明通道的方向.只要明白,代码的书写顺序是从左到右就马上掌握通道的方向是怎样的.

    因为channel是一个引用类型,所以在它被初始化之前,它的值是nil , channel使用make函数进行初始化.可以向它传递一个int值,代表channel缓冲区的大小(容量),构造出来的 是一个缓冲性的channel: 不传或传0的,构造的就是一个非缓冲性的channel.

    两者有一些差别: 非缓冲型channel无法缓冲元素,对它的操作一定顺序是"发送->接收->发送->接收->....",如果想连续向一个非缓冲chan发送2个元素,并且没有接收的话,第一次一定会被阻塞;对于缓冲型channel的操作,则要"宽松"一些,毕竟是带了"缓冲"光环.

    image-20221125144205052

    对chan的发送和接收操作都会在编译期间转换成为底层的发送接收函数.

    Channel分为两种: 带缓冲、不带缓冲.怼不带缓冲的channel进行的操作实际上可以看作"同步模式",带缓冲的则称为"异步模式".

    同步模式下,发送方和接收方要同步就绪,只有在两者都ready的情况下,数据才能在两者之间传输(后面会看到,实际上就是内存拷贝).否则,任意一方先进行发送或接收操作,都会被挂起,等另一方的出现才能被唤醒.

    异步模式下,在缓冲槽可用的情况下(有剩余容量),发送和接收操作都可以顺利进行.否则,操作的一方(如写入)同样会被挂起,知道出现相反操作(如接收)才会被唤醒.

    小结: 同步模式下,必须要使发送方和接收方配对,操作才会成功,否则会被阻塞;异步模式下,缓冲槽要有剩余容量,操作才能成功,否则也会被阻塞.

    简单来说,CSP模型由并发执行的实体(线程或者进程或者协程)所组成,实体之间通过发送消息进行通信,这里发送消息时使用的就是通道,或者叫channel.

    CSP模型的关键是关注channel,而不是关注发送消息的实体.Go语言实现了CSP部分理论,goroutine对应CSP中并发执行的实体,channel也就对应着CSP中的channel.

    # 四、Goroutine

    Goroutine是实际并发执行的实体,它底层使用协程(coroutine)实现并发,coroutine是一种运行在用户态的用户线程,类似于greenthread,go底层选择使用coroutine的出发点是因为,它具有如下特点:

    • 用户空间避免了内核态和用户态的切换导致的成本
    • 可以由语言和框架层进行调度
    • 更小的栈空间允许创建大量的实例

    可以看到第二条 用户空间线程的调度不是由操作系统来完成的,像在java 1.3中使用的grennthread的是由JVM统一调度的(后java)已经改为内核线程,还有ruby中的fiber(半协程)是需要重新中自己进行调度的,而goroutine是在golang层面提供了调度器,并且对网络IO库进行了封装,屏蔽了复杂的细节,对外提供统一的语法关键字支持,简化了并发程序编写的成本.

    # 五、Goroutine调度器

    Go并发调度: G-P-M模型

    在操作系统提供的内核线程之上,Go搭建了一个特有的两级线程模型.goroutine机制实现了M: N的线程模型,goroutine机制是线程(coroutine)的一种实现,golang内置的调度器,可以让多核CPU中每个CPU执行一个协程.

    image-20221125150737980

    # 六、总结

    Golang的channel将goroutine隔离开,并发编程的时候可以将注意力放在channel上.在一定程度上,这个和消息队列的解耦功能还是挺像的.上面主要介绍了一些channel的常规操作.

    Go通过channel和goroutine之后,Go的并发编程变得异常容易和安全,得以让程序员把注意力留到业务上去,实现开发效率的提升.

    要知道,技术并不最重要的,它只是实现业务的工具.一门高效的开发语言可以把节省下来的时间,留着去做更多有意义的事情.

    CSP最早是由Tony Hoare在1977年提出,据说至今这个理论模型还是更新,

    查阅电子版本: http://www.usingcsp.com/cspbook.pdf.

    上次更新: 2024/04/09, 16:48:42
    select语句
    Go语言反射(一)

    ← select语句 Go语言反射(一)→

    最近更新
    01
    AWS NAT-NetWork-Firwalld配置(一)
    04-09
    02
    AWS NAT-NetWork-Firwalld配置(二)
    04-09
    03
    kubernetes部署minio对象存储
    01-18
    更多文章>
    Theme by Vdoing | Copyright © 2019-2024 Bruce Tao Blog Space | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式