【问题标题】:How to optimize thread safe queue in Go?如何优化 Go 中的线程安全队列?
【发布时间】:2021-11-18 22:30:52
【问题描述】:

我有以下请求队列:

type RequestQueue struct {
    Requests []*http.Request
    Mutex *sync.Mutex
}

func (rq *RequestQueue) Enqueue(req *http.Request) {
    rq.Mutex.Lock()
    defer rq.Mutex.Unlock()
    rq.Requests = append(rq.Requests, req)
}

func (rq *queue) Dequeue() (*http.Request, error) {
    rq.Mutex.Lock()
    defer rq.Mutex.Unlock()
    if len(rq.Requests) == 0 {
        return nil, errors.New("dequeue: queue is empty")
    }
    req := rq.Requests[0]
    rq.Requests = rq.Requests[1:]
    return req, nil
}

是否可以只使用 atomic 包而不使用 Mutex,类型只是 type AtomicRequestQueue []*http.Request,这会带来任何性能优势吗?

【问题讨论】:

  • 不,您需要在此处进行互斥锁提供的同步。为什么不使用已经在运行时高度优化的简单缓冲通道?
  • @JimB 因为 afaik tt 无法动态调整大小。
  • 这很少是一个真正的问题,因为无论如何都应该以某种方式限制最大大小,并且通道具有在缓冲区满时能够自动阻塞的好处。
  • 可以动态调整大小...

标签: go concurrency queue thread-safety


【解决方案1】:

使用频道,例如chan *http.Request。通道实际上是一个 FIFO 队列。

您调用的Enqueue 将只是一个发送操作c <- req,而您调用的Dequeue 将只是一个接收操作req := <-c

是否可以仅使用 atomic 包来做到这一点

您没有说明这个线程安全队列的真正目的是什么,但是您上面介绍的用例似乎需要同步,即 mutual ex对共享资源的独占访问。 atomic 包中的类型只保证操作的结果将被其他线程以一致的方式观察到。不涉及互斥。

如果您的队列需要比实际显示更多的业务逻辑,则通道可能过于原始;在这种情况下,互斥锁可能是您最好的选择。如果您希望有大量读取,您可以使用sync.RWMutex 来减少锁争用。

【讨论】:

    猜你喜欢
    • 2014-04-07
    • 1970-01-01
    • 2012-11-13
    • 2014-10-27
    • 2018-08-15
    • 1970-01-01
    • 2012-05-30
    • 2012-11-05
    • 2012-12-26
    相关资源
    最近更新 更多