1.goroutine&线程
  1. 大小: 线程1~8MB 协程2KB
  2. 调度: 线程由操作系统调度 每个线程占用cpu的一段时间 线程的上下文切换涉及 用户态->内核态->用户态的转换、成本us级
       协程由runtime调度 每个协程占用线程的一段时间 协程的上下文切换 只在用户态 成本ns级
  3. 阻塞: 线程被内核挂起让出cpu,涉及上下文切换
       G在执行用户态调用时阻塞 G被runtime挂起,立刻运行下一个准备好了的协程
       G在执行系统调用时阻塞 handoff: 见下图
  4. 调用: 系统调用: 例如读写文件、读写socket(go这里做的比较好阻塞时只有G被挂起)
       用户态调用: 例如等channel可写/读 等锁 等条件变量
  5. ⬑ 协程调度
2.内存逃逸
  1. 定义: 内存的生命周期变化 导致原本分配在栈上的内存逃逸到堆上需要GC 比如子函数返回内存的指针、内存被另外一个协程使用
  2. 如何查看逃逸
    developer@srv-005:/data/src/phgames/api/rpc/knock/games/goldmaster
    $ go build -tags goldmaster -gcflags="-m" -o /dev/null
    # phgames/api/rpc/knock/games/goldmaster
    ./knock.go:29:9: &Tap{...} escapes to heap
    ./knock.go:45:20: make([]*protoKnock.GoldMasterSpin, 0) escapes to heap
    ./playerExt.go:33:9: &PlayerExt{...} escapes to heap
  3. 编译参数
    -gcflags="all=-N -l"  //开发服使用 -N关闭优化 -l关闭内联
3.GC
  1. GC的触发条件: Runtime会维护一个NextGC变量(下次GC阈值) & 定时触发 & 业务代码调用runti.GC()生成环境一般不用会影响性能
  2. 黑灰白 白:不可达内存/或者更准确一点GC不知道它存在的内存(所有内存初始状态为白) 黑:可达内存 灰:等待变黑的内存(以及子指针待扫描)
  3. GC流程 stw: stop the world
    Root Scan //stw扫描所有根对象 全局变量/栈/CPU寄存器
    ↓
    并发Mark  //1.顺藤摸瓜 把根对象里面的子对象加入到灰队列,自己变成黑
              //2.写屏障:有如果有指针改变指向,把指针后面指向的内存加到灰队列里面去
              //3.消费灰队列,自己变黑,子对象加入到灰队列 这是个递归循环
              //4.灰队列消费差不多以后执行下一步
    ↓
    Mark Termination //消费灰队列
                     //这里要stw的原因 1.把可达的新内存加入到灰队列里面并不是一个原子操作 涉及寄存器硬件延时 会导致新内存还没被标识灰在下一步会被GC干掉
                                    //2.业务协程可以疯狂的创建白色内存,需要stw停下来,最后扫描一次栈
    ↓
    Concurrent Sweep //标识为白的内存回收
  4. 如何减少GC压力
    sync.Pool(对象池)
    对象复用
    减少临时对象
    预分配slice
    strings.Builder(字符串拼接 扩容次数少)
4.http&websocket&socket
  1. http: 一问一答,服务器不能主动发消息给客户端,客户端想拿到服务器的主动消息 只能轮询。文本协议,属于应用层
  2. websocket: 解决了http上面的痛点,支持服务器向客户端主动推送消息。属于应用层
  3. socket: 操作系统提供的底层接口 不属于4/7层协议
5.进程间通讯
  1. socket -> (tcp/udp)
  2. gRPC
    包括:系列化/反序列化/连接池/http2多路复用(无序)/消息头/粘包拆包/Keepalive/重连(部分场景)/超时
    不包括:业务处理顺序/业务心跳/幂等/消息去重
    htt2多路复用:可以简单理解为把消息分解成帧用一个tcp发送,就会导致消息到达服务器是无序的。
          实际是消息被分成帧在多个stream上分时复用一个tcp链路发给服务器,同一个消息的多个帧只能在一个stream上,在同一个stream的消息到达服务器是有序的
  3. HTTP
  4. MQ
  5. redis
6.进程内通讯
  1. channel 环形队列+不可读/写阻塞协程且把协程加入到对应队列(sendq recvq)+可读/写状态从0->1唤醒+线程安全
    不会扩容,初始化时容量就固定了 make(chan T, 64)
    make(chan T) 无缓冲接收双方必须都到场 否则到场方阻塞
    v, ok := <-ch ok=false为写已关闭 关闭时v为默认初始化值
    向已关闭的channel写数据会panic 所以谁写谁关闭 多个协程写channel的时候 如果要关闭可以用屏障确保多个协程都不会再写channel才能关闭
  2. 共享内存+锁
  3. 条件变量
  4. atomic
  5. WaitGroup屏障
7.context
  1. 用于请求生命周期管理。客户端断开、超时、主动取消时,服务器可以通过case <-ctx.Done():或者ctx.Err()!=nil感知到。
    主要应用于等io的时候,例如mysql查询,go服务器收到客户端取消以后可以回收mysql连接,mysql会停止查询
  2. ctx树结构,ctx2, cancel2 := context.WithCancel(ctx1) ctx2是ctx1的子节点,父节点取消任务时子节点会收到通知,子节点取消任务时父节点不会受到通知
  3. ctx可以携带traceId,在打印日志的时候把traceId打印出来可以知道是哪一次请求的日志,避免两次相同的请求打印的日志混淆
8.go的多态 reflect&interface&any
  1. interface c++的纯虚类
  2. any等价interface{} 任意数据的容器
  3. reflect拆解容器的工具
    reflect.Type   //类型
    -- Name()      //类型名
    -- Kind()      //类型底层类型 struct/slice/map/ptr/int/string/bool/func
    -- Elem()      //获取内部元素类型  比如获取ptr的指向类型 slice内的元素类型 map内的元素类型
    -- Key()       //map 的key
    -- In/Out      //函数 参数/返回值的类型
    -- NumMethod   //类 公开函数个数
    -- Size        //占用内存大小
    reflect.ValueOf //值
    val := reflect.ValueOf(&User{}).Elem()
    typ := reflect.TypeOf(&User{}).Elem()
    for i := 0; i < val.NumField(); i++ { //遍历结构体字段
     field := val.Field(i)                //第i个字段值
     fieldName := typ.Field(i).Name       //第i个字段的名字
    }
    for i := 0; i < typ.NumMethod(); i++ { //遍历调用类的函数
     m := typ.Method(i)
     fn := m.Func
     fn.Call([]reflect.Value{})
    }
9.go项目命令
go mod init project-name                                      //新项目 创建go.mod文件
go env -w GOPROXY=https://goproxy.cn,direct                   //设置七牛代理
go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/         //设置阿里云代理
go env GOPROXY                                                //查看环境变量
go mod tidy                                                   //自动整理依赖
go get github.com/gin-gonic/gin@v1.9.1                        //添加依赖
go mod graph                                                  //查看依赖关系树
go build                                                      //编译
go run                                                        //当作脚本来执行
文档更新时间: 2026-06-30 16:28   作者:morninglu