Go底层八股笔记
Go 原生 map 不是并发安全的,多协程同时读写会panic: concurrent map read/write。
解决方法
互斥锁
1 | package main |
读写锁
1 | var mu sync.RWMutex |
性能高于互斥锁
go原生并发安全map
1 | package main |
已关闭channel读写
往已经关闭的 channel 写数据
→ 直接 panic(panic: send on closed channel)
从已经关闭的 channel 读数据
→ 不会 panic
防击穿
方案 1:互斥锁(mutex lock)
只允许一个请求去数据库查数据并重建缓存,其他请求等待。
优点:简单、安全、无数据不一致
缺点:高并发下有少量阻塞
1 | if 缓存存在 { |
方案 2:热 Key 永不过期
热 Key 不设置过期时间,彻底杜绝失效。
更新方式:
- 后台异步线程定时刷新缓存
- 或数据变化时主动更新
优点:完全不会击穿
缺点:需要额外维护刷新逻辑
方案 3:提前异步刷新 Key
在 Key 快要过期前,主动异步刷新。
流程:
- 给 Key 设置过期时间
- 每次访问时判断:是否快过期了?
- 快过期 → 异步去 DB 拉新数据重新写入缓存
优点:无感知、无阻塞
缺点:实现稍复杂
方案 4:本地缓存(Caffeine)+ 二级缓存
热 Key 同时存放于:
- Redis(分布式缓存)
- 本地缓存(应用内内存)
Redis 失效 → 还能读本地缓存,不会直接打数据库。
优点:性能极高、抗击穿
缺点:要注意数据一致性
RDB vs AOF
| 对比项 | RDB | AOF |
|---|---|---|
| 原理 | 全量快照 | 记录写命令 |
| 文件内容 | 二进制数据(紧凑) | 文本命令(可读) |
| 恢复速度 | 极快 | 慢(要重放命令) |
| 数据安全性 | 低(可能丢最后几分钟数据) | 高(最多丢 1 秒) |
| 文件大小 | 小 | 大(会膨胀) |
| 性能影响 | 高(fork 子进程,阻塞瞬间) | 低(异步刷盘) |
| 适用场景 | 冷备、全量恢复 | 实时持久化、高可靠 |
SLICE不是线程安全的
因为slice 底层结构不是原子的
包含:指针 + 长度(len) + 容量(cap)
多协程同时修改这三个值,没有任何锁保护。
进程线程协程
进程:操作系统资源分配的最小单位(独立房子)
线程:CPU 调度的最小单位(房子里的工人)
协程:用户态轻量级执行单元(工人手里的小任务)
如果Zset做排行榜时要获取某个分数范围内的用户,应该使用哪个命令
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
两协程交替打印1-100
1 | package main |
jwt相关
1. JWT 的组成部分
JWT 由三部分组成,用 . 分隔:
- Header(头部):声明加密算法、token 类型
- Payload(载荷):存放业务数据(用户信息)
- Signature(签名):防篡改校验串
格式:Header.Payload.Signature
2. Payload 部分存什么?
存非敏感的公开业务信息,标准字段 + 自定义字段:
- 标准:
sub(用户ID)、iss(签发者)、exp(过期时间) - 自定义:用户名、角色、权限、手机号(不存密码、密钥)
3. 其他用户能看到 Payload 吗?
能!完全能!
- Payload 只是 Base64 编码,不是加密
- 任何人都可以直接解码看到明文
- 绝对不能存敏感信息(密码、身份证、密钥)
总结
- JWT = 头部 + 载荷 + 签名
- Payload 存公开用户信息,不存敏感数据
- Payload 可被任何人查看,仅防篡改,不保密
m3u8
早期完整视频是单个 MP4 文件,缺点:
大文件加载慢、卡顿;
无法动态切换清晰度;
防盗链、防盗录难度低。
于是把完整视频切成很多小段 TS 分片(通常每片几秒),再用 m3u8 文件记录所有分片的 URL、播放顺序。
播放器 / 下载器先读取 m3u8,再按顺序逐个加载 TS 片段,拼接播放。
约束解码
用于强制让llm输出标准结构的输出
模型每次算下一个 Token 的概率分布(logits),约束解码在采样前加一层 “掩码(Mask)”:
用 JSON Schema / Pydantic 类定义合法结构
实时跑一个语法解析器(有限状态机 FSM / 上下文无关文法 CFG)
只允许符合当前语法状态的 Token 参与采样;非法 Token 概率直接设为 -∞(永远不会被选)
千问不支持。
goMap
Go 语言中的 map 是无序的!
遍历的时候每次顺序都不一样,不保证插入顺序,也不保证排序顺序。
为了防止开发者依赖遍历顺序
Go runtime 在遍历的时候故意做了随机化




