GMP 中 work stealing 机制

获取 P 本地队列,当从绑定 P 本地 runq 上找不到可执行的 g,尝试从全局链 表中拿,再拿不到从 netpoll 和事件池里拿,最后会从别的 P ...

GMP 调度流程

每个 P 有个局部队列,局部队列保存待执行的goroutine(流程 2),当 M 绑定的 P 的的局部队列已经满了之后就会把 goroutine 放到全...

0 之前 GM 调度模型

调度器把 G 都分配到 M 上,不同的 G 在不同的 M 并发运行时,都需要向系统申 请资源,比如堆栈内存等,因为资源是全局的,就会因为资源竞争照成很多性...

GMP 指的是什么

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

Goroutine 定义

Golang 在语言级别支持协程,称之为 Goroutine。Golang 标准库提供的所有 系统调用操作(包括所有的同步 I/O 操作),都会出让 CP...

sync.Pool 有什么用

对于很多需要重复分配、回收内存的地方,sync.Pool 是一个很好的选择。频 繁地分配、回收内存会给 GC 带来一定的负担,严重的时候会引起 CPU 的...

什么是 CAS

CAS 的全称为 Compare And Swap,直译就是比较交换。是一条 CPU 的原子指 令,其作用是让 CPU 先进行比较两个值是否相等,然后原子...

原子操作和锁的区别

原子操作由底层硬件支持,而锁则由操作系统的调度器实现。 锁应当用来保护一段逻辑,对于一个变量更新的保护。 原子操作通常执行上会更有效率,并且更能利用计算机...

什么操作叫做原子操作

原子操作即是进行过程中不能被中断的操作,针对某个值的原子操作在被进行 的过程中,CPU 绝不会再去进行其他的针对该值的操作。为了实现这样的严谨 性,原子操...

什么是 sync.Once

-  Once 可以用来执行且仅仅执行一次动作,常常用于单例对象的初始化场 景。 -  Once 常常用来初始化单例资源,或者并发访问只需初始化一次的共享...

WaitGroup 实现原理

WaitGroup 主要维护了 2 个计数器,一个是请求计数器 v,一个是等待计数 器 w,二者组成一个 64bit 的值,请求计数器占高 32bit,等...

WaitGroup 用法

一个 WaitGroup 对象可以等待一组协程结束。使用方法是:main 协程通过调用 wg.Add(delta int) 设置 worker 协程的个数...

Cond 中 Wait 使用

func (c *Cond) Wait() Wait()会自动释放 c.L 锁,并挂起调用者的 goroutine。之后恢复执行, Wait()会在返回时...

Cond 是什么

Cond 实现了一种条件变量,可以使用在多个 Reader 等待共享资源 ready 的场 景(如果只有一读一写,一个锁或者 channel 就搞定了)每...

RWMutex 注意事项

-  RWMutex 是单写多读锁,该锁可以加多个读锁或者一个写锁 -  读锁占用的情况下会阻止写,不会阻止读,多个 Goroutine 可以同时获取 读...

RWMutex 实现

通过记录 readerCount 读锁的数量来进行控制,当有一个写锁的时候,会将读 锁数量设置为负数 1<<30。目的是让新进入的读锁等待之前...

Mutex 允许自旋的条件

锁已被占用,并且锁不处于饥饿模式。积累的自旋次数小于最大自旋次数(active_spin=4)。CPU 核数大于 1。有空闲的 P。当前 Goroutin...

Mutex 正常模式和饥饿模式

正常模式(非公平锁) 正常模式下,所有等待锁的 goroutine 按照 FIFO(先进先出)顺序等待。唤醒 的 goroutine 不会直接拥有锁,而是...

Mutex 几种状态

mutexLocked — 表示互斥锁的锁定状态;mutexWoken — 表示从正常模式被从唤醒;mutexStarving — 当前的互斥锁进入饥饿状...

Channel 的 ring buffer 实现

channel 中使用了 ring buffer(环形缓冲区) 来缓存写入的数据。ring  buffer 有很多好处,而且非常适合用来实现 FIFO 式...

介绍一下 Channel

Go 语言中,不要通过共享内存来通信,而要通过通信来实现内存共享。Go 的 CSP(Communicating Sequential Process)并发...

Golang Map 查找

Go 语言中 map 采用的是哈希查找表,由一个 key 通过哈希函数得到哈希值,64 位系统中就生成一个 64bit 的哈希值,由这个哈希值将 key ...

Golang Map 底层实现

Golang 中 map 的底层实现是一个散列表,因此实现 map 的过程实际上就是实现 散表的过程。在这个散列表中,主要出现的结构体有两个,一个叫 hm...

Golang 的参数传递、引用类型

Go 语言中所有的传参都是值传递(传值),都是一个副本,一个拷贝。因为拷 贝的内容有时候是非引用类型(int、string、struct 等这些),这样就...

扩容前后的 Slice 是否相同?

情况一:  原数组还有容量可以扩容(实际容量没有填充完),这种情况下,扩容以后的 数组还是指向原来的数组,对一个切片的操作可能影响多个指针指向相同地址 的...

Golang Slice 的底层实现

切片是基于数组实现的,它的底层是数组,它自己本身非常小,可以理解为对 底层数组的抽象。因为基于数组实现,所以它的底层的内存是连续分配的,效 率非常高,还可...

Go 两个接口之间可以存在什么关系?

如果两个接口有相同的方法列表,那么他们就是等价的,可以相互赋值。如果接口A的方法列表是接口B的方法列表的自己,那么接口B可以赋值给接口A。接口查询是否成功...

Go 程序中的包是什么?

包 (pkg) 是 Go 工作区中包含 Go 源文件或其他包的目录。源文件中的每个函数、变量和类型都存储在链接包中。每个 Go 源文件都属于一个包,该包在...