一种无阻塞读写 channel 的方法
前情概要
最近设计了线程模型:
- 所有的请求在 handler 中进行简单读和计算处理,
- 所有关于资源竞争的操作都被提交到一个单独的线程去统一处理
因为资源竞争的处理环境是绝对串行,所以在这个单独的线程中完全无锁。这样的设计下就要求:
- 该线程不会被阻塞
- 线程中单个逻辑尽可能简单,不能成为性能的瓶颈
如果能做到这两个要求,那么一个绝对简单的线程处理逻辑就出现了,全程无锁的设计要多爽有多爽。
这个线程与上下游的交互参考生产者消费者模型,使用阻塞队列(go 中的带缓冲的 channel 天然适配)来进行共享数据,印证了 go 设计中不要使用共享内存来通信,使用通信来共享内存
的理念。
但是这个设计的实现难点就是如果保证这个调度线程不会被阻塞,特别是在对 channel 进行操作的时候,如果 channel 的缓冲区被填满或者当前缓冲区没有数据怎么处理?
PS: 如果可以避免,最好不要在主流逻辑中使用可能阻塞的 channel 读,完全可以放在 select 中作为逻辑开始的信号。
是否有一种对 channel 操作无阻塞的方法?
无阻塞读
1 | func NoBlockedRead(ch chan int) (int, error){ |
无阻塞写
1 | func NoBlockedWrite(ch chan int, input int) error { |
根据不同需求,可以包装成一个带 timeout 的无阻塞读/写
1 | func TimeoutRead(timeout time.Duration, ch chan int) (int, error) { |
那么问题来了,这样的实现,会不会影响到后续的读写呢?
这就要引申出另一个问题了?
chan 内部究竟是如何实现的, 待补