正常的情况下,redis是请求响应模式,一条请求后那么正常就会返回一个响应,例如上图。但是只存在这种情况是无法满足我们开发的需求的。所以redis给我们提供了管道。
redis的管道(pipeline )相关特点:
下面我们来看一下redigo提供了哪些接口给我们。
type Conn interface {
// Close closes the connection.
Close() error
// Err returns a non-nil value when the connection is not usable.
Err() error
// Do sends a command to the server and returns the received reply.
Do(commandName string, args ...interface{}) (reply interface{}, err error)
// Do = Send + Flush + Receive
// Send writes the command to the client's output buffer.
Send(commandName string, args ...interface{}) error
// Flush flushes the output buffer to the Redis server.
Flush() error
// Receive receives a single reply from the Redis server
Receive() (reply interface{}, err error)
}
重点讲解Do和Send、Flush、Receive的关系。
redis的主要作用上面也说过,就是节省大量的网络耗时,减少与redis的交互,主要体现在TCP三次握手与四次挥手。
// 1. 批量发送,批量接收。
c.Send(cmd1, ...)
c.Send(cmd2, ...)
c.Send(cmd3, ...)
c.Flush() // 将上面的三个命令发送出去
c.Receive() // cmd1 的返回值
c.Receive() // cmd2 的返回值
c.Receive() // cmd3 的返回值
// 2. 如果不需要关注返回值。
c.Send(cmd1, ...)
c.Send(cmd2, ...)
c.Send(cmd3, ...)
c.Do("")
// 简单分析Do(""):
// Do=Send、Flush、Receive。而此时传空字符串,那么此时的Send相当于没命令即没意义,
// 那么此时的Do("")等价于连续执行了c.Flush()与c.Receive(),并不关心返回值。
// 3. 如果只关注最后一个命令的返回值。
// 一般这种情况前两条是写,第三条语句是读。
c.Send(cmd1, ...)
c.Send(cmd2, ...)
c.Do(cmd3, ...)
但是注意,上面每次调用函数后,都应该去判断返回值,养成良好的习惯,不是说忽略了redis的返回值就不判断错误。
例如忽略返回值但判断错误情况:
ifi( _, err := c.Do("")); err != nil{
// 错误处理
}
package main
import (
"fmt"
"math/rand"
"time"
"github.com/garyburd/redigo/redis"
)
func main() {
//c, err := redis.Dial("tcp", fmt.Sprintf("%s:%d", "127.0.0.1", 6379))
c, err := redis.Dial("tcp", "192.168.1.9:6379", redis.DialPassword("123456"))
if err != nil {
panic(err)
}
defer (func() {
fmt.Println("connection close")
c.Close()
})()
// 1. 批量发送,批量接收。
if false {
c.Send("del", "set", "list", "zset")
c.Send("sadd", "set", "tyy", "hc", "lqq")
c.Send("lpush", "list", 10001, 10002, 10003)
c.Send("smembers", "set")
c.Send("lrange", "list", 0, -1)
c.Flush()
c.Receive() // 忽略del的返回值。
c.Receive() // 忽略sadd的返回值。
c.Receive() // 忽略lpush的返回值。
mbrs, err := redis.Strings(c.Receive()) // 接收smembers返回值。
if err != redis.ErrNil {
fmt.Println(mbrs)
}
lsts, err := redis.Ints(c.Receive()) // 接收lrange返回值。
if err != redis.ErrNil {
fmt.Println(lsts)
}
}
// 2. 如果不需要关注返回值。
if false {
c.Send("del", "set", "list", "zset")
c.Send("sadd", "set", "tyy", "hc", "lqq")
c.Send("lpush", "list", 10001, 10002, 10003)
c.Do("")
}
// 3. 如果只关注最后一个命令的返回值。
if false {
rand.Seed(time.Now().UnixNano())
c.Send("del", "set", "list", "zset")
c.Send("sadd", "set", "tyy", "hc", "lqq")
{
args := redis.Args{}.Add("zset")
args = args.Add(rand.Intn(100)).Add("tyy")
args = args.Add(rand.Intn(100)).Add("hc")
args = args.Add(rand.Intn(100)).Add("lqq")
c.Send("zadd", args...)
}
// 只关注最后一个命令的返回值。
{
args := redis.Args{}.Add("zset")
args = args.Add(0).Add(-1).Add("withscores")
vals, err := redis.Values(c.Do("zrange", args...))
if err != nil {
panic(err)
}
var rets []struct {
Name string
Score int
}
if err = redis.ScanSlice(vals, &rets); err != nil {
panic(err)
}
fmt.Println(rets)
}
}
}
测试方法:将上面的3个if添加中的false逐个改成true即可测得下面结果。
分别对应上面的结果: