go 并发队列、优先级队列、延迟队列

并发队列

并发阻塞队列与channel对比

并发队列channel
并发控制加锁天然支持
性能锁竞争可能影响性能无锁设计、性能不错,适合高并发场景
阻塞机制需要自行控制等待机制,如使用sync.Cond天然支持
代码灵活性支持复杂管理,比如:
1. 遍历,如sql.DB freeConn处理过期连接
2. 下标访问,如sql.DB连接健康检查——随机访问
3. 优先级、权重排序
4. 查看队首、队尾元素,判断出队时机
FIFO,相较来说,支持简单操作

需求分析

功能性需求
  • 线程安全 锁
  • 队列为空时阻塞消费者or返回错误;队列满时阻塞生产者or返回错误;
    • 阻塞超时阻塞
  • 扩容问题
    • 考虑大容量对GC的影响
  • 元素优先级、权重
  • 持久化
    • 应用关闭时持久化数据,重启后恢复
非功能性需求
  • 公平性与效率

    • 是不是先到先得,尤其阻塞情况下
    • channel不是公平的
      • 效率:占着资源刚来的更容易抢到锁,因为资源分配有消耗
      • 饥饿模式:队列等待时间太长进入饥饿模式后容易抢到锁
  • 性能

    • ringBuffer替代[]*T

      好处:b.queue = b.queue[1:]会引起内存频繁分配,ringBuffer复用固定资源

    • 链表替代ringBuffer

      好处: ringBuffer使用固定内存,可能实际不需要,链表支持动态连接

      ringBuffer比链表的优势:支持复杂操作,如随机访问

接口设计

type Queue[T any] interface {
	Enqueue(ctx context.Context, t *T) error
	Dequeue(ctx context.Context) (*T, error)
}

实现方案一:切片实现

要点
  • 并发控制:加锁

  • 队列使用ringBuffer

  • 使用cond进行超时阻塞控制

    • 由于sync.cond没有超时控制,所以自行设计cond

    • 等待时使用for,而不是if // 广播唤醒多个,但只有一个抢到了锁,其他需要重新等待枪锁

      for b.queue.IsFull() { 
      	err := b.notFull.WaitV2(ctx)
      	if err != nil {
      		return err
      	}
      }
      
源码

gitee: https://gitee.com/luyue_zhang/channel/blob/master/queue/concurrency_queue/slice_queue.go

实现方案二:链表实现

要点
  • 并发控制:无锁实现,自旋(for循环)+ CAS
  • 链表在高并发场景下无法提供准确的isFull、isEmpty、isLen值
源码

gitee: https://gitee.com/luyue_zhang/channel/blob/master/queue/concurrency_queue/link_queue.go

加锁实现与CAS+自旋对比

加锁CAS+自旋
抢锁阻塞住时,不会有超高CPU消耗,但由于等待锁时间较长,时差较大抢锁时会一直占用Processor,资源消耗高;
锁竞争越强,效果越差,CPU消耗越多;
ringBuffer并发队列不能使用自旋+CAS,可能兜了一圈又回来了

优先级队列

要点

  • 入队时需要排序
    • 优先级队列引入排序,不适合使用ringBuffer、链表,使用slice

源码

gitee: https://gitee.com/luyue_zhang/channel/tree/master/queue/priority_queue

相关库

container/heap

延迟队列

要点

  • 延迟队列是按照时间排序的优先级队列
  • 元素出队逻辑:
    • 队首元素Delay() <=0 直接出队
    • 队首元素Delay() > 0,阻塞等待:
      • 等待过程中超时返回
      • 等待时间到达,则重新循环一次。因为释放了锁,可能元素已经被人取走了,所以需要重新循环判断一下;如果合法,下次将会从!t.Delay().After(now)出去
      • 收到信号:新入队元素Delay() < 当前元素的Delay(),则再次循环。// 比起简单重置计时器更安全、可靠;因为等待过程中,元素可能已经发生变动

源码

gitee: https://gitee.com/luyue_zhang/channel/tree/master/queue/delay_queue

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值