golang利用redis实现消息队列Push和Pop

可以利用redis的list结构来实现消息队列功能,使用lpush、rpush来实现入队,lpop、rpop来实现出队列。

我们统一从左边push、从右边pop,即用lpush和rpop组合。

当list中没有元素时,rpop会返回nil,这样我们需要不断用轮询队列,直到队列中有元素,然后pop出来。

为了避免不断轮询带来的性能损耗,我们这里使用brpop命令,brpop使用了系统提供的阻塞原语,在队列中没有元素时,就会一直阻塞或者超出设置时间返回,当队列中有元素时,会执行rpop命令并返回。

  • Push

list的lpush支持单个或者多个元素的push,为了编写更通用的方法,我们实现批量push的功能

import "github.com/garyburd/redigo/redis"

func BatchPushQueue(queueName string, keys []string) (err error) {
	if len(keys) == 0 {
		return
	}
	con := pool.Get()
	defer con.Close()
	_, err = con.Do("lpush", redis.Args{}.Add(queueName).AddFlat(keys)...)
	return
}
  • Pop

brpop会一致阻塞住直到队列中有元素,但是它支持设置timeout,当阻塞时间超过timeout时,pop会返回nil。当timeout设置为0时,表示阻塞时间无限制。

brpop支持监听多个list,因此它有两个返回值,第一个返回值是list的名称,即key的名称,第二个返回值是pop出来的元素。我们只是监听一个list,因此我们会取返回值中的第二个元素。

//timeout is seconds which command 'brpop' will block when queue is empty.
func PopQueue(queueName string, timeout int) (data string, err error) {
	con := pool.Get()
	defer con.Close()
	nameAndData, err := redis.Strings(con.Do("brpop", queueName, timeout))
	if err != nil {
		if err == redis.ErrNil {
			err = nil
			return
		}
		return
	}
	if len(nameAndData) > 1 {
		data = nameAndData[1]
	}
	return
}

 

你可能感兴趣的:(Golang学习,redis)