Go
select
go select思想来源于网络IO模型中的select,本质上也是IO多路复用,只不过这里的IO是基于channel而不是基于网络,同时go select也有一些自己不同的特性。
特性:
-
每个case都必须是一个通信
-
所有channel表达式都会被求值
-
所有被发送的表达式都会被求值
-
如果任意某个通信可以进行,它就执行;其他被忽略。
-
如果有多个case都可以运行,select会随机公平地选出一个执行。其他不会执行。否则执行default子句(如果有)
-
如果没有default字句,select将阻塞,直到某个通信可以运行;Go不会重新对channel或值进行求值。
冷知识:select 使用 c语言 的AsyncCall2函数 该函数执行时间为 200ms
问题:分别指定耗时50ms,200ms,3000ms,select打印最先完成的异步调用耗时,预想:50ms 先 200ms 后,结果:50ms 与 200ms 随机出现
用途
-
结合特性5,6,可以通过带 default 语句的 select 实现非阻塞读写
-
结合特性2,每次 select 都会对所有通信表达式求值,因此可通过 time.After简洁实现定时器功能,并且定时任务可通过 done channel 停止
-
结合特性4,如果多个case满足读写条件,select会随机选择一个语句执行
context
context.Context 是用来设置截止日期、同步信号,传递请求相关值的结构体。
在 Goroutine 构成的树形结构中对信号进行同步以减少计算资源的浪费是 context.Context 的最大作用
每一个 context.Context 都会从最顶层的 Goroutine 一层一层传递到最下层。context.Context 可以在上层 Goroutine 执行出现错误时,将信号及时同步给下层
当最上层的 Goroutine 因为某些原因执行失败时,下层的 Goroutine 由于没有接收到这个信号所以会继续工作;但是当我们正确地使用 context.Context 时,就可以在下层及时停掉无用的工作以减少额外资源的消耗
defer
defer 是否会在panic后执行
interface
- writing generic algorithm
- hiding implementation detail
- providing interception points
interface拥有两个指针 一个指向类型 一个指向具体值
slice
分配在连续的内存地址上
元素类型一致,元素存储宽度一致
空间大小固定,不能修改
可以通过索引计算出元素对应存储的位置(只需要知道数组内存的起始位置和数据元素宽度即可)
会出现数据溢出的问题(下标越界)
slice扩容
如果新的slice大小是当前大小2倍以上,则大小增长为新大小
如果当前slice cap 小于1024,按每次2倍增长,否则每次按当前大小1/4增长。直到增长的大小超过或等于新大小
append的实现是在内存中将slice的array值赋值到新申请的array上
性能
通过上面我们知道slice的扩容涉及到内存的拷贝,这样带来的好处是数据存储在连续内存上,比随机访问快很多,最直接的性能提升就是缓存命中率会高很多,这也就是为什么slice不采用动态链表实现的原因吧
我们知道拷贝内存数据是有开销的, 而其中最大的开销不在 memmove
数据上,而是在开辟一块新内存malloc及之后的GC压力
拷贝连续内存是很快的,随着cap变大,拷贝总成本还是 O(N) ,只是常数大了
假如不想发生拷贝,那你就没有连续内存。此时随机访问开销会是:链表 O(N)
当你能大致知道所需的最大空间(在大部分时候都是的)时,在make的时候预留相应的 cap 就好 如果需要的空间很大,而且每次都不确定,那就要在浪费内存和耗 CPU 在 malloc + gc 上做权衡 链表的查找操作是从第一个元素开始,所以相对数组要耗时间的多,因为采用这样的结构对读的性能有很大的提高
mysql
性能调优
SQL优化
小表驱动大表 limit限定 索引添加 适当添加冗余字段,减少表关联。
系统优化
max_connections 最大连接数
innodb_buffer_pool_size 数据缓冲区buffer pool大小
sort_buffer_size 排序缓冲区内存大小
join_buffer_size 使用连接缓冲区大小
read_buffer_size 全表扫描时分配的缓冲区大小
缓存
主动式缓存 用户更新数据 同时更新缓存
被动式缓存 用户更新数据 删除缓存,被读取时载入缓存
Maps
线程不安全
底层使用的hash结构
hash算法使用aes hash hash值分为 高位hash和低位hash
高位哈希值:是用来确定当前的bucket(桶)有没有所存储的数据的 bmap a bucket for a Go map
低位哈希值:是用来确定,当前的数据存在了哪个bucket(桶)hmap a header for a go map