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
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章