BLPOP命令相关(BRPOP完全一样)
- List存在且长度大于0,返回key name和pop出来的元素
- List存在且为空时,如果直到timeout之后都还是为空,就返回nil
- List不存在时,将在timeout之后返回nil
- BLPOP用在一个不是List的数据上,将会返回error
Code
func Blpop(c redis.Conn) {
// use BLPOP normally
c.Do("RPUSH", "sun", "rise")
results, err := redis.Strings(c.Do("BLPOP", "sun", 3))
if err != nil {
colorlog.Error(err.Error())
return
}
fmt.Println("Popped element belongs to list:", results[0])
fmt.Println("Popped element's value:", results[1])
// If list is null, will return nil after timeout
c.Do("RPOP", "sun")
result, err := c.Do("BLPOP", "sun", 3)
if err != nil {
colorlog.Error(err.Error())
return
}
if result == nil {
fmt.Println("If list is null, will return nil after timeout.")
}
// If key doesn't exist, will return nil after timeout
c.Do("DEL", "bug")
result, err = c.Do("BLPOP", "bug", 3)
if err != nil {
colorlog.Error(err.Error())
return
}
if result == nil {
fmt.Println("If key doesn't exist, will return nil after timeout.")
}
// If use BLPOP on a key that is not a list, will return error
c.Do("SET", "kkk", 12)
_, err = c.Do("BLPOP", "kkk", 3)
if err != nil {
fmt.Println("If use BLPOP on a key that is not a list, will return error:")
colorlog.Error(err.Error())
}
}
Output
➤ go run main.go
Popped element belongs to list: sun
Popped element's value: rise
If list is null, will return nil after timeout.
If key doesn't exist, will return nil after timeout.
If use BLPOP on a key that is not a list, will return error:
[ERR]2020/04/14 15:15:11 WRONGTYPE Operation against a key holding the wrong kind of value
- BLPOP是LPOP的block版本,尝试一下当List为空时,在BLPOP的timeout之前,向List添加一个元素。
另外,BRPOPLPUSH的实验方法跟BLPOP几乎一样。
Code
func main() {
c1, err := redis.Dial("tcp", "127.0.0.1:6379")
if err != nil {
fmt.Println("Connect to redis error", err)
return
}
defer c1.Close()
c2, err := redis.Dial("tcp", "127.0.0.1:6379")
if err != nil {
fmt.Println("Connect to redis error", err)
return
}
defer c2.Close()
c1.Do("RPOP", "sun")
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
fmt.Println("BLPOP start:", time.Now().Format("2006/1/2 15:04:05"))
results, err := redis.Strings(c1.Do("BLPOP", "sun", 20))
fmt.Println("BLPOP end:", time.Now().Format("2006/1/2 15:04:05"))
if err != nil {
fmt.Println("BLPOP error")
colorlog.Error(err.Error())
}
if results != nil {
fmt.Println("Popped element belongs to list:", results[0])
fmt.Println("Popped element's value:", results[1])
} else {
fmt.Println("Null list")
}
}()
go func() {
defer wg.Done()
fmt.Println("Wait for 6 seconds:", time.Now().Format("2006/1/2 15:04:05"))
time.Sleep(6 * time.Second)
fmt.Println("RPUSH start:", time.Now().Format("2006/1/2 15:04:05"))
rpushResult, err := redis.Int(c2.Do("RPUSH", "sun", "red"))
if err != nil {
fmt.Println("RPUSH error")
colorlog.Error(err.Error())
}
fmt.Println("rpushResult:", rpushResult)
}()
wg.Wait()
}
Output
➤ go run main.go
Wait for 6 seconds: 2020/4/14 15:27:22
BLPOP start: 2020/4/14 15:27:22
RPUSH start: 2020/4/14 15:27:28
BLPOP end: 2020/4/14 15:27:28
Popped element belongs to list: sun
Popped element's value: red
rpushResult: 1
可以看到,BLPOP在22秒时开始,6秒之后,也就是28秒,RPUSH开始,也就在这一瞬间,List里有了元素,所以在28秒时BLPOP也就结束了,不会等到tiemout。
至于单独把这个阻塞的实验用另一个单独的函数来做,是因为需要两个
redis.conn
。
在这个"github.com/garyburd/redigo/redis"
包里,conn
实现的Do()
函数里,调用的DoWithTimeout()
函数。
而DoWithTimeout()
函数里,conn
是用了互斥锁的
func (c *conn) Do(cmd string, args ...interface{}) (interface{}, error) {
return c.DoWithTimeout(c.readTimeout, cmd, args...)
}
func (c *conn) DoWithTimeout(readTimeout time.Duration, cmd string, args ...interface{}) (interface{}, error) {
c.mu.Lock()
pending := c.pending
c.pending = 0
c.mu.Unlock()
...
网友评论