扫码订阅《 》或入驻星球,即可阅读文章!

GOLANG ROADMAP

阅读模式

  • 沉浸
  • 自动
  • 日常
首页
Go学习
  • Go学院

    • Go小课
    • Go视界
    • Go小考
    • Go实战
  • Go资源

    • 优质课程
    • 在线宝典
    • 资源下载
    • 帮找资源
训练营 🔥
  • Go体系课&实战训练营
  • 升值加薪陪跑训练营
Go求职
  • 求职刷题

    • 企业题库
    • 面试宝典
    • 求职面经
  • 求职服务

    • 内推互助
    • 求职助力
    • 内推公司
Go友会
  • 城市
  • 校园
推广返佣
  • 返佣排行
  • 返佣规则
  • 推广学院
实验区
  • Go周边
  • Go宝典

    • 推荐图书
    • 精品博文
  • Go开源

    • Go仓库
    • Go月刊
更多
  • 用户中心

    • 我的信息
    • 我的返佣
    • 我的消息
  • 玩转星球

    • 星球介绍
    • 星主权益
    • 吐槽专区
    • 成长记录
  • 合作交流

    • 商务合作
    • 讲师招募
    • 生态伙伴
author-avatar

GOLANG ROADMAP


首页
Go学习
  • Go学院

    • Go小课
    • Go视界
    • Go小考
    • Go实战
  • Go资源

    • 优质课程
    • 在线宝典
    • 资源下载
    • 帮找资源
训练营 🔥
  • Go体系课&实战训练营
  • 升值加薪陪跑训练营
Go求职
  • 求职刷题

    • 企业题库
    • 面试宝典
    • 求职面经
  • 求职服务

    • 内推互助
    • 求职助力
    • 内推公司
Go友会
  • 城市
  • 校园
推广返佣
  • 返佣排行
  • 返佣规则
  • 推广学院
实验区
  • Go周边
  • Go宝典

    • 推荐图书
    • 精品博文
  • Go开源

    • Go仓库
    • Go月刊
更多
  • 用户中心

    • 我的信息
    • 我的返佣
    • 我的消息
  • 玩转星球

    • 星球介绍
    • 星主权益
    • 吐槽专区
    • 成长记录
  • 合作交流

    • 商务合作
    • 讲师招募
    • 生态伙伴
  • 面试宝典系列

    • Golang面试题汇总
  • 宝典内容

    • 1.Golang中除了加Mutex锁以外还有哪些方式安全读写共享变量
    • 2.无缓冲Chan的发送和接收是否同步?
    • 3.Golang并发机制以及它所使用的CSP并发模型
    • 4.Golang中常用的并发模型
    • 5.Go中对nil的Slice和空Slice的处理是一致的吗?
    • 6.协程和线程和进程的区别?
    • 7.Golang的内存模型中为什么小对象多了会造成GC压力?
    • 8.Go中数据竞争问题怎么解决?
    • 9.什么是channel,为什么它可以做到线程安全?
    • 10.Golang垃圾回收算法?
    • 11.GC的触发条件
    • 12.Go的GPM如何调度?
    • 13.并发编程概念是什么?
    • 14.Go语言的栈空间管理是怎么样的?
    • 15.Goroutine和Channel的作用分别是什么?
    • 16.怎么查看Goroutine的数量?
    • 17.Go中的锁有哪些?
    • 18.怎么限制Goroutine的数量?
    • 19.Channel是同步的还是异步的?
    • 20.Goroutine和线程的区别?
    • 21.Go的Struct能不能比较?
    • 22.Go的defer原理是什么?
    • 23.Go的select可以用于什么?
    • 24.Context包的用途是什么?
    • 25.Go主协程如何等其余协程完再操作?
    • 26.Go的Slice如何扩容?
    • 27.Go中的map如何实现顺序读取?
    • 28.Go中CAS是怎么回事?
    • 29.Go中的逃逸分析是什么?
    • 30.Go值接收者和指针接收者的区别?
    • 31.Go的对象在内存中是怎样分配的?
    • 32.栈的内存是怎么分配的?
    • 33.堆内存管理怎么分配的?
    • 34.Go中的defer函数使用下面的两种情况下结果是什么?
    • 35.在Go函数中为什么会发生内存泄露?
    • 36.Go中new和make的区别?
    • 37.G0的作用?
    • 38.Go中的锁如何实现?
    • 39.Go中的channel的实现?
    • 40.Go中的map的实现
    • 41.Go中的http包的实现原理?
    • 42.Goroutine发生了泄漏如何检测?
    • 43.Go函数返回局部变量的指针是否安全?
    • 44.Go中两个Nil可能不相等吗?
    • 45.Goroutine和KernelThread之间是什么关系?

扫码订阅《 》或入驻星球,即可阅读文章!

3.Golang并发机制以及它所使用的CSP并发模型


面试宝典
Golang并发机制以及它所使用的CSP并发模型

在计算机科学中,通信顺序过程(communicating sequential processes,CSP)是一种描述并发系统中交互模式的正式语言,它是并发数学理论家族中的一个成员,被称为过程算法(process algebras),或者说过程计算(process calculate),是基于消息的通道传递的数学理论。

CSP模型是上个世纪七十年代提出的,不同于传统的多线程通过共享内存来通信,CSP讲究的是“以通信的方式来共享内存”。用于描述两个独立的并发实体通过共享的通讯 channel(管道)进行通信的并发模型。 CSP中channel是第一类对象,它不关注发送消息的实体,而关注与发送消息时使用的channel。

Golang中channel 是被单独创建并且可以在进程之间传递,它的通信模式类似于 boss-worker 模式的,一个实体通过将消息发送到channel 中,然后又监听这个 channel 的实体处理,两个实体之间是匿名的,这个就实现实体中间的解耦,其中 channel 是同步的一个消息被发送到 channel 中,最终是一定要被另外的实体消费掉的,在实现原理上其实类似一个阻塞的消息队列。

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

它具有以下特点:

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

Golang中的Goroutine的特性:

Golang内部有三个对象: P对象(processor) 代表上下文(或者可以认为是cpu),M(work thread)代表工作线程,G对象(goroutine).

正常情况下一个cpu对象启一个工作线程对象,线程去检查并执行goroutine对象。碰到goroutine对象阻塞的时候,会启动一个新的工作线程,以充分利用cpu资源。 所有有时候线程对象会比处理器对象多很多.

我们用如下图分别表示P、M、G:

G(Goroutine): 我们所说的协程,为用户级的轻量级线程,每个Goroutine对象中的sched保存着其上下文信息。

M(Machine): 对Os内核级线程的封装,数量对应真实的CPU数(真正干活的对象)。

P(Processor): 逻辑处理器,即为G和M的调度对象,用来调度G和M之间的关联关系,其数量可通过GOMAXPROCS()来设置,默认为核心数。

在单核情况下,所有Goroutine运行在同一个线程(M0)中,每一个线程维护一个上下文(P),任何时刻,一个上下文中只有一个Goroutine,其他Goroutine在runqueue中等待。

一个Goroutine运行完自己的时间片后,让出上下文,自己回到runqueue中(如下图所示)。

当正在运行的G0阻塞的时候(可以需要IO),会再创建一个线程(M1),P转到新的线程中去运行。

当M0返回时,它会尝试从其他线程中“偷”一个上下文过来,如果没有偷到,会把Goroutine放到Global runqueue中去,然后把自己放入线程缓存中。 上下文会定时检查Global runqueue。

Golang是为并发而生的语言,Go语言是为数不多的在语言层面实现并发的语言;也正是Go语言的并发特性,吸引了全球无数的开发者。

Golang的CSP并发模型,是通过Goroutine和Channel来实现的。

Goroutine 是Go语言中并发的执行单位。有点抽象,其实就是和传统概念上的”线程“类似,可以理解为”线程“。 Channel是Go语言中各个并发结构体(Goroutine)之前的通信机制。通常Channel,是各个Goroutine之间通信的”管道“,有点类似于Linux中的管道。

通信机制channel也很方便,传数据用channel <- data,取数据用<-channel。

在通信过程中,传数据channel <- data和取数据<-channel必然会成对出现,因为这边传,那边取,两个goroutine之间才会实现通信。

而且不管是传还是取,肯定阻塞,直到另外的goroutine传或者取为止。

因此GPM的简要概括即为: 事件循环,线程池,工作队列.