并发客户端的Goroutines或锁

时间:2015-04-22 13:44:38

标签: concurrency go

通常在编写具有多个goroutine的并发程序时,这些goroutine需要访问客户端,例如编写REST API,其中每个HTTP处理程序需要使用单个初始化的Redis客户端来读取和写入Redis实例。

我要么有一个带有互斥锁的客户端实例,所以只有一个goroutine可以在任何时候使用它或者有一个客户端goroutine,其他goroutine可以通过一个通道请求读取。这两种方式都有效,但我想知道哪种更惯用?谢谢你的帮助

1 个答案:

答案 0 :(得分:2)

如果您只有一个客户端,并且只对其执行简单操作,请使用互斥锁。它通常简单易懂,不像带有一堆通道和select语句的goroutine。请务必封装线程安全,以免给用户带来锁定负担。

比较

var (
    mutex sync.Mutex
    resource = 0
)

func Inc() int {
    mutex.Lock()
    defer mutex.Unlock()
    resource++
    return resource
}

使用:

var requests = make(chan chan int)

func init() {
    go func() {
        resource := 0
        for {
            response := <- requests
            resource++
            response <- resource
        }
    }()
}

func Inc() int {
    response := make(chan int)
    requests <- response
    return <-response
}

前者显然更简洁和可维护。特别是如果资源不是全局的,那么渠道方法还需要手动管理goroutine,因为goroutine不是垃圾收集的(参见how to stop a goroutine)。

如果您不介意拥有多个客户端,请使用一组客户端。 go-redis支持开箱即用的池。池本身是线程安全的,可用于获取其中一个空闲连接。