最近需要做一个本地缓存的需求,缓存数据从 redis 读取
遂考虑到在大量并发的情况下,减少 go 协程切换的消耗,考虑用自旋锁来实现
大概的思路是:
- 大量并发请求
- 自旋锁上锁
- 放一个 goroutine 去 redis 读取数据到本地缓存
- 其他 goroutine 原地自旋等待缓存数据
- 读取的协程读取到数据之后解锁
但是我经过实际测试,发现用自旋锁的速度和用互斥锁的速度要差1~2个数量级,遂很不理解
之后我经过大量测试发现:
- 自旋锁在 本地操作(值自增),阻塞操作(sleep 或者 channel recv)时,性能高于互斥锁
- 在 HTTP 操作时性能和互斥锁相当
- 在通过 "github.com/go-redis/redis/v8" 操作 redis 获取数据时,自旋锁的性能和互斥锁要差1个数量级
不知道是否有大佬可以解答一番?不吝赐教
[测试代码在这里](https://github.com/Mericusta/go-foo/tree/main/src/sync-foo)
这个做法不敢苟同,如果读取redis的时间很长(事实上也是很慢,单次往返肯定在毫秒级别),并发量大的时候cpu空转的时间非常长。正确的做法绝对是先使用原子操作,判断当前是否有缓存,如果没有,使用channel等待,自旋锁100%会降低吞吐量
#9
更多评论