Go

select

go select思想来源于网络IO模型中的select,本质上也是IO多路复用,只不过这里的IO是基于channel而不是基于网络,同时go select也有一些自己不同的特性。

特性:

  1. 每个case都必须是一个通信

  2. 所有channel表达式都会被求值

  3. 所有被发送的表达式都会被求值

  4. 如果任意某个通信可以进行,它就执行;其他被忽略。

  5. 如果有多个case都可以运行,select会随机公平地选出一个执行。其他不会执行。否则执行default子句(如果有)

  6. 如果没有default字句,select将阻塞,直到某个通信可以运行;Go不会重新对channel或值进行求值。

冷知识:select 使用 c语言 的AsyncCall2函数 该函数执行时间为 200ms

问题:分别指定耗时50ms,200ms,3000ms,select打印最先完成的异步调用耗时,预想:50ms 先 200ms 后,结果:50ms 与 200ms 随机出现

用途

  1. 结合特性5,6,可以通过带 default 语句的 select 实现非阻塞读写

  2. 结合特性2,每次 select 都会对所有通信表达式求值,因此可通过 time.After简洁实现定时器功能,并且定时任务可通过 done channel 停止

  3. 结合特性4,如果多个case满足读写条件,select会随机选择一个语句执行


context

context.Context 是用来设置截止日期、同步信号,传递请求相关值的结构体。

在 Goroutine 构成的树形结构中对信号进行同步以减少计算资源的浪费是 context.Context 的最大作用

每一个 context.Context 都会从最顶层的 Goroutine 一层一层传递到最下层。context.Context 可以在上层 Goroutine 执行出现错误时,将信号及时同步给下层

当最上层的 Goroutine 因为某些原因执行失败时,下层的 Goroutine 由于没有接收到这个信号所以会继续工作;但是当我们正确地使用 context.Context 时,就可以在下层及时停掉无用的工作以减少额外资源的消耗

defer

defer 是否会在panic后执行

interface

  1. writing generic algorithm
  2. hiding implementation detail
  3. 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

参考

go select机制与常见的坑



下一页