3

Often when writing concurrent programs with multiple goroutines, those goroutines require access to a client, for instance writing a REST API where each HTTP handler needs to use a single initialized Redis client to read and write to the Redis instance.

I either have a client instance with a mutex lock so only one goroutine can use it at any one time OR have a client goroutine which the other goroutines can request a read via a channel. Both ways work but I am wondering which is more idiomatic? Thanks for your help

1 Answers1

2

If you have only one client, and only simple operations to perform on it, use a mutex. It's typically simple and easy to understand, unlike a goroutine with a bunch of channels and a select statement. Be sure to encapsulate the thread-safety in order not to burden the API user with locks.

Compare:

var (
    mutex sync.Mutex
    resource = 0
)

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

With:

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
}

The former is clearly more concise and maintainable. And especially if the resource isn't global, the channel approach also requires manual management of goroutines since goroutines aren't garbage-collected (see how to stop a goroutine).


If you don't mind having more than one client, use a pool of clients. go-redis supports pooling out of the box. The pool itself is thread-safe and can be used to acquire one of the idle connections.

Community
  • 1
  • 1
  • The redigo package also has a [`redis.Pool`](http://godoc.org/github.com/garyburd/redigo/redis#Pool) if that's one's preferred client lib. – JimB Apr 22 '15 at 13:52
  • @rightfold Thanks very much, this has made my day far easier :) – charlesworth Apr 22 '15 at 15:03