事务块 multi
redis中的 multi
方法,提供了一个队列用于缓存多个指令,在客户端调用 exec
后将该队列中的指令批量执行,执行过程中不会被其他指令干扰(具有原子性)。
客户端每发送一个指令后,客户端都需要等待服务端返回状态,以表示该指令是否已经添加到队列中。
在客户端调用 exec
后,redis将执行该队列中的所有指令,并按原顺序返回执行结果的数组。
PHP代码演示:
$redis->multi()
->set('key1', 'val1')
->get('key1')
->set('key2', 'val2')
->get('key2')
->exec();
返回数据:
array(
0 => true,
1 => 'val1',
2 => true,
3 => 'val2'
);
管道 pipeline
官方对于管道的说明 https://redis.io/docs/manual/pipelining 中有一段对于管道的描述:
A Request/Response server can be implemented so that it is able to process new requests even if the client hasn't already read the old responses. This way it is possible to send multiple commands to the server without waiting for the replies at all, and finally read the replies in a single step.
管道其实是客户端提供的一种技术,服务端还是按照收到一条消息、执行一条消息、返回一条消息的正常流程。客户端通过对管道中的指令列表改变读写顺序可以大幅节省IO时间。管道中指令越多,效果越好。
PHP代码演示:
$redis->pipeline()
->ping()
->multi()->set('x', 42)->incr('x')->exec()
->ping()
->multi()->get('x')->del('x')->exec()
->ping()
->exec();
返回数据:
array(
0 => '+PONG',
1 => [true, 43],
2 => '+PONG',
3 => [43, 1],
4 => '+PONG'
);
multi和pipeline的区别
不同点
原子性
multi
是事务,整个操作具有原子性,所有指令在执行过程中不会被其他指令干扰。
pipeline
没有原子性,客户端相当于还是在发送一个一个的指令
执行过程
multi
每发送一个指令,都要等待服务端返回接收状态后才能发送下一条,服务端收到exec后才会执行队列中的所有指令
pipeline
将所有指令打包,然后一次性发送到服务器,服务端收到指令包后进行拆分再一条一条执行
相同点
所有指令的执行结果都是在最后以一个数组的形式返回的,结果的顺序与指令发送的顺序一致。
其他
值得注意的是,PHP的 Redis 类中的 multi
方法支持参数 $mode
,默认为 MULTI
:
/**
* Enter and exit transactional mode.
*
* @param int $mode Redis::MULTI|Redis::PIPELINE
* Defaults to Redis::MULTI.
* A Redis::MULTI block of commands runs as a single transaction;
* a Redis::PIPELINE block is simply transmitted faster to the server, but without any guarantee of atomicity.
* discard cancels a transaction.
*
* @return static|Redis returns the Redis instance and enters multi-mode or Redis if in multi mode
* Once in multi-mode, all subsequent method calls return the same object until exec() is called.
*/
public function multi($mode = Redis::MULTI) {}