go知识简单整理
2023-02-03 14:37:53 28 举报
AI智能生成
go知识简单整理
作者其他创作
大纲/内容
常用包
fmt
println:不支持格式化输出,所有参数以%v(默认格式)输出
printf:支持格式化输出
unsafe
Sizeof:求变量所占字节大小
json
Marshal
序列化结构体,返回字节数组和err,data, err := json.Marshal(test)
Unmarshal
反序列化结构体,err := json.Unmarshal(data, &test)
runtime
获取一些系统属性和手动调用gc
bufio
os
sync
模型及概念
gmp: g 代表协程,m代表系统线程,p代表调度器
变量逃逸:go不像c++,new不一定是在堆上分配内存 ,如果分配的对象不会在此函数作用域外被引用,则会分配在栈上,否则分配在堆上。
函数
make
用于chan,slice,map的创建并返回其引用
new
为一个变量声明空间,并返回其地址,保存在指针中
delete
用于删除map中的值,例如:delete(m, 1)
copy()
切片复制, 深拷贝
defer
指定执行过程,在退出当前函数体时执行。当声明了多个defer操作后,defer的执行过程是和栈一样,后进先出
若函数内声明了defer操作,又发生了异常,那么也会先将defer操作执行完后,才抛出异常
捕获的变量在捕获时确定
接口
定义方式:type error interface { Error() string }
若某个结构体实现了一个接口定义的方法,那么该接口变量即可指向该结构体,类似基类子类的关系
反射 reflect
可以获得变量的类型和值,没怎么用过
gmp
go协程
协程的时候只需要保存寄存器值和栈指针以及栈大小,这就是切换时的上下文,类似c++中的context库实现
m线程
p队列
特性
流程式,编译式语言
使用静态库,某些依赖第三方库的情况下也会链接动态库
内存逃逸
如果一个函数结束之后外部没有引用,那么优先分配到栈中(如果申请的内存过大,栈区存不下,会分配到堆)。
如果一个函数结束之后外部还有引用,那么必定分配到堆中
申请大内存变量可能会逃逸到堆上
编译期间不确定变量类型的话,那么也会发生逃逸
堆上动态内存分配的开销比栈要大很多,所以有时我们传递值比传递指针更有效率。因为复制是栈上完成的操作,开销要比变量逃逸到堆上再分配内存要少的多
通过go build -gcflags '-m -m -l'命令查看到逃逸分析的结果
为了减少gc压力,一些传参可以用值传递,以空间换时间
gc
观测
GODEBUG=gctrace=1 GODEBUG是控制runtime包的一个环境变量 gctrace=1表示每次进行gc时进行信息打印
"runtime/trace"
有了 GC,为什么还会发生内存泄露?
当有一个全局对象时,可能不经意间将某个变量附着在其上,且忽略的将其进行释放,则该内存永远不会得到释放。
goroutine一直不退出泄露
GOGC
GOGC 是Go Runtime最早支持的环境变量,甚至比GOROOT还早,几乎无人不知。GOGC 用于控制GC的处发频率, 其值默认为100,
意为直到自上次垃圾回收后heap size已经增长了100%时GC才触发运行。
意为直到自上次垃圾回收后heap size已经增长了100%时GC才触发运行。
主流回收方法
引用计数法
追踪式垃圾回收
三色标记法
比标记清扫多一个灰色节点的步骤,主要是解决stw长时间挂起的问题
标记清扫
根节点:全局变量,函数栈,寄存器值指针
基础类型
string
string内部数据结构是一个指向值字符串的指针ptr和字符串长度len
string内的字符串是一个不可改变的字节序列,string间的拷贝只是ptr和len的拷贝
string的第i个字节不一定是第i个字符,因为对于非ASCII字符的UTF8编码会是2个及以上字节
rune
go的字符类型可不是char!
rune是int32, byte是uint8,byte更多代表raw data
常量
用const修饰,如 const i string = test, 其中string可省略
数组
声明方式如:q := [3]int{1,2,3}
go语言中,数组类型包括值类型和数组长度,二者缺一不可
切片
声明方式:s := make([]int, 3, 10), 此时切片的长度就是3,容量是10
数据结构:指向底层数组的指针ptr,切片的长度len,从此切片头部到底层数组尾部的长度cap
寻值:切片只能寻找len范围内的值,即使是在cap范围内也不行,否则会引起panic异常
操作:len()函数取切片长度,cap函数取容量,append函数向末尾添加值
删除切片内元素只能以[X:Y]的方式,创建子切片
扩容: append() 当扩容超出原有容量时,会生成新切片,原来的切片会被丢弃
小切片按照2倍扩容,大切片按照1.25倍扩容
面试问题
数组和切片有什么区别
数组编译时确定大小
切片动态扩容
拷贝大切片一定比拷贝小切片代价大吗?
切片数据结构只是包含三个成员:ptr,len,cap,拷贝只是复制这三个成员,所以不一定
切片的深浅拷贝
copy:深拷贝
=操作符 : 浅拷贝
[:]下标的方式复制: 浅拷贝
map
声明方式:m := make(map[string]int)
map中的元素不可取地址:禁止对map元素取址的原因是map可能随着元素数量的增长而重新分配更大的内存空间,从而可能导致之前的地址无效。
判断map中是否存在一个元素,可以: t, ok := m["exist"]; ok
map的遍历是无序的,因为其在遍历开始前会生成一个随机数作为hash后桶的起点
go中没有提供set类型,可以用map来实现:map[int]bool, if !map[2] {map[2] = true}, 通过对布尔值的判断就可以确定唯一
对map求长度,使用len函数
删除map中元素,用delete
结构体
声明方式:type test struct {}
空结构体占用字节数为0,适合配合chan进行并发控制
因为go中的传参都是以拷贝的方式进行的,所以对于大结构体,可以用指针进行传参
如果结构体内的所有成员都是可以比较的,那么结构体本身也可以比较
goroutine
一个 goroutine 的栈只占几 KB,但这个栈空间也是可以伸缩的
在未超出最大容量之前按照两倍系数增加
连续堆栈
寻址容易,需要大片内存,管理简单
分段堆栈
寻址复杂,对于大片内存要求不高,管理复杂
chan
用作go协程之间通信的通道,分为有缓存通道和无缓存通道
当通道内无值或者空间已满,发送协程或者接收协程会被阻塞
当需要从多个chan获取数据,可以使用select
协程对chan的访问默认是阻塞的,想要非阻塞的访问就把chan放在select中,条件不满足就会从select退出,既不会阻塞
mutex
mutex还存在RW锁,和其他语言提供的一样
互斥锁
读写锁
var wg sync.WaitGroup
var wg sync.WaitGroup
go不支持可重入锁,trylock,以及自旋锁,要自己实现
cas
子主题
子主题
WaitGroup
等待协程退出
常用函数:Add,Done,Wait
sync.Once
保证函数在程序内只执行一次,调用Do方法
Context
用于父子协程里共享上下文变量和父子协程同步
匿名函数(闭包)
panic & recover
panic, recover, defer 三个操作经常一起搭配出现
类型断言
可基于类型断言识别错误类型
go性能分析优化
pperf
调试手段
gdb
dlv
0 条评论
下一页