y以下是我的go学习之路,仅供参考
https://juejin.cn/post/7038967716459315208
go入门
https://studygolang.com/articles/35591
go底层
1、最常用的调试 golang 的 bug 以及性能问题的实践方法? 2、Golang的协程调度器原理及GMP设计思想? 3、Golang中逃逸现象, 变量“何时栈?何时堆?” 4、Golang中make与new有何区别? 5、Golang三色标记+混合写屏障GC模式全分析 6、面向对象的编程思维理解interface 7、Golang中的Defer必掌握的7知识点 8、精通Golang项目依赖Go modules 9、一站式精通Golang内存管理
1、数据定义 2、数组和切片 3、Map 4、interface 5、channel 6、WaitGroup
1、流?I/O操作?阻塞?epoll? 2、分布式从ACID、CAP、BASE的理论推进 3、对于操作系统而言进程、线程以及Goroutine协程的区别 4、Go是否可以无限go? 如何限定数量? 5、单点Server的N种并发模型汇总 6、TCP中TIME_WAIT状态意义详解 7、动态保活Worker工作池设计
接口
类型
断言
空接口.(具体类型)
非空接口.(具体类型)
空接口.(非空接口)
就算能从缓存中查到对应的itab,也要进一步判断itab.fun[0]是否等于0,这是因为断言失败的类型组合其对应的itab结构体也会被缓存起来,只是会把itab.fun[0]置为0,用以表明这里的动态类型并没有实现对应的接口,这样以后在遇到同种类型断言时,就不用再去检查方法列表了,直接断言失败
非空接口.(非空接口)
类型断言的关键是明确接口的动态类型以及对应的类型实现了哪些方法,而明确这些的关键还是类型元数据
method
方法本质上就是函数,只不过在调用时,接收者会作为第一个参数传入
给内置类型定义方法是不被允许的
而接口类型是无效的方法接收者
局部变量a没有被修改
实现了修改
指针调用值的方法,值调用指针的方法
所以,本质是来说,方法表达式和方法变量都是funcval
panic
defer 最大的功能是 panic 后依然有效 所以defer可以保证你的一些资源一定会被关闭,从而避免一些异常出现的问题。
没有recover发生时,panic执行defer的方式,先标记后释放,目的是为了终止之前发生的panic
所有在panic链表上的项都会被输出,顺序与panic发生的顺序一致
recover
移除并跳出当前的panic
defer
1.12
defer函数如果含参,会先把参数确定下来,再进入g._defer中
https://www.kancloud.cn/aceld/golang/1958310
执行时从头开始
go语言会预先分配不同规格的defer池,没有空闲的或没有大小合适的就再进行堆分配
1.13
官方说提升30%
1.14
提升一个量级,但panic更慢了
闭包
为啥f不直接指向地址呢,还要通过一个funcval的结构体呢?
addr1为函数A的入口地址,addr2为funcval结构体的地址,没有捕获列表的funcval在编译阶段会做出优化,就是在只读数据段分配一个共用的funcval结构体
除了初始化赋值外,在任何地方都没被修改,直接拷贝值到捕获列表中就行
就是要保持捕获变量在外层函数与闭包函数中的一致性,由于捕获变量i初始化后被修改过,所以i在堆上分配,并在栈中存i的地址
Golang的sync.Map
golang sync.mutex
https://www.bilibili.com/video/BV15V411n7fM/
// 互斥锁的公平性。 // // 互斥锁有两种运行模式:正常模式和饥饿模式。 // 在正常模式下,请求锁的goroutine会按 FIFO(先入先出)的顺序排队,依次被唤醒,但被唤醒的goroutine并不能直接获取锁,而是要与新请求锁的goroutines去争夺锁的所有权。 // 但是这其实是不公平的,因为新请求锁的goroutines有一个优势:他们正在cpu上运行且数量可能比较多,所以新唤醒的goroutine在这种情况下很难获取锁。在这种情况下,如果这个goroutine获取失败,会直接插入到队列的头部。 // 如果一个等待的goroutine超过1ms时仍未获取到锁,会将这把锁转换为饥饿模式。 // // 在饥饿模式下,互斥锁的所有权会直接从解锁的goroutine转移到队首的goroutine。 // 并且新到达的goroutines不会尝试获取锁,会直接插入到队列的尾部。 // // 如果一个等待的goroutine获得了锁的所有权,并且满足以下两个条件之一: // (1) 它是队列中的最后一个goroutine // (2) 它等待的时间少于 1 毫秒(hard code在代码里) // 它会将互斥锁切回正常模式。 // // 普通模式具有更好的性能,因为即使有很多阻塞的等待锁的goroutine,一个goroutine也可以尝试请求多次锁。 // 而饥饿模式则可以避免尾部延迟这种bad case。
|
|
- state字段就是这把mutex的状态,二进制低3位对应锁的状态,将state右移3位代表waiter的数量。
- sema(信号量)用来唤醒goroutine。
|
|
lock
|
|
unlock
|
|
常见坑点
1.sync.mutex不可重入
- 例如如果连续调用两次lock,会触发死锁,goroutine直接panic。
- 如果A获取A+B,B获取B+A,会触发死锁
2.sync.mutex,尝试去unlock一把空闲的mutex,会导致panic。
3.sync.mutex不与goroutine绑定,可由a goroutine获取锁,b goroutine释放锁。
4.不要复制sync.Mutex,mutex做函数参数时,传参时使用指针。