Python Redis pipeline操作
Redis是建立在TCP协议基础上的CS架构,客户端client对redis server采取请求响应的方式交互。
一般来说客户端从提交请求到得到服务器相应,需要传送两个tcp报文。
设想这样的一个场景,你要批量的执行一系列redis命令,例如执行100次get key,这时你要向redis请求100次+获取响应100次。如果能一次性将100个请求提交给redis server,执行完成之后批量的获取相应,只需要向redis请求1次,然后批量执行完命令,一次性结果,性能是不是会好很多呢?
答案是肯定的,节约的时间是客户端client和服务器redis server之间往返网络延迟的时间。这个时间可以用ping命令查看。
网络延迟高:批量执行,性能提升明显
网络延迟低(本机):批量执行,性能提升不明显
某些客户端(java和python)提供了一种叫做pipeline的编程模式用来解决批量提交请求的方式。
这里我们用python客户端来举例说明一下。
1、pipeline
网络延迟
client与server机器之间网络延迟如下,大约是30ms。

测试用例
分别执行其中的try_pipeline和without_pipeline统计处理时间。
# -*- coding:utf-8 -*- import redis
import time
from concurrent.futures import ProcessPoolExecutor r = redis.Redis(host='10.93.84.53', port=6379, password='bigdata123') def try_pipeline():
start = time.time()
with r.pipeline(transaction=False) as p:
p.sadd('seta', 1).sadd('seta', 2).srem('seta', 2).lpush('lista', 1).lrange('lista', 0, -1)
p.execute()
print time.time() - start def without_pipeline():
start = time.time()
r.sadd('seta', 1)
r.sadd('seta', 2)
r.srem('seta', 2)
r.lpush('lista', 1)
r.lrange('lista', 0, -1)
print time.time() - start def worker():
while True:
try_pipeline() with ProcessPoolExecutor(max_workers=12) as pool:
for _ in range(10):
pool.submit(worker)
结果分析
try_pipeline平均处理时间:0.04659
without_pipeline平均处理时间:0.16672
我们的批量里有5个操作,在处理时间维度上性能提升了4倍!
网络延迟大约是30ms,不使用批量的情况下,网络上的时间损耗就有0.15s(30ms*5)以上。而pipeline批量操作只进行一次网络往返,所以延迟只有0.03s。可以看到节省的时间基本都是网路延迟。
2、pipeline与transation
pipeline不仅仅用来批量的提交命令,还用来实现事务transation。
这里对redis事务的讨论不会太多,只是给出一个demo。详细的描述你可以参见这篇博客。redis事务
细心的你可能发现了,使用transaction与否不同之处在与创建pipeline实例的时候,transaction是否打开,默认是打开的。
# -*- coding:utf-8 -*- import redis
from redis import WatchError
from concurrent.futures import ProcessPoolExecutor r = redis.Redis(host='127.0.0.1', port=6379) # 减库存函数, 循环直到减库存完成
# 库存充足, 减库存成功, 返回True
# 库存不足, 减库存失败, 返回False
def decr_stock(): # python中redis事务是通过pipeline的封装实现的
with r.pipeline() as pipe:
while True:
try:
# watch库存键, multi后如果该key被其他客户端改变, 事务操作会抛出WatchError异常
pipe.watch('stock:count')
count = int(pipe.get('stock:count'))
if count > 0: # 有库存
# 事务开始
pipe.multi()
pipe.decr('stock:count')
# 把命令推送过去
# execute返回命令执行结果列表, 这里只有一个decr返回当前值
print pipe.execute()[0]
return True
else:
return False
except WatchError, ex:
# 打印WatchError异常, 观察被watch锁住的情况
print ex
pipe.unwatch() def worker():
while True:
# 没有库存就退出
if not decr_stock():
break # 实验开始
# 设置库存为100
r.set("stock:count", 100) # 多进程模拟多个客户端提交
with ProcessPoolExecutor(max_workers=2) as pool:
for _ in range(10):
pool.submit(worker)
Python Redis pipeline操作的更多相关文章
- Python Redis pipeline操作和Redis乐观锁保持数据一致性
Redis是建立在TCP协议基础上的CS架构,客户端client对redis server采取请求响应的方式交互. redis 乐观锁:也可理解为版本号比较机制,主要是说在读取数据逇时候同时读取其版本 ...
- Python Redis pipeline操作(秒杀实现)
设想这样的一个场景,你要批量的执行一系列redis命令,例如执行100次get key,这时你要向redis请求100次+获取响应100次.如果能一次性将100个请求提交给redis server,执 ...
- Python --Redis Hash操作
一.Redis Hash操作 Redis 数据库hash数据类型是一个string类型的key和value的映射表,适用于存储对象.Redis 中每个 hash 可以存储 232 - 1 键值对(40 ...
- Python Redis常用操作(持续更新)
目录 1.Redis简介 2.Redis部署 3.Redis API应用 4.String操作 1.Redis简介 redis是业界主流的key-value,nosql数据库之一.和Memcached ...
- python:redis简单操作
一,安装redis-py pip install redis easy_install redis 二,简单用法 import redis # 连接redis服务器 def conn_redis(): ...
- python redis list操作
LPUSH list_name value [value ...] Prepend one or multiple values to a list 从左侧插入值,最早插入的值在最右边 LPUSHX ...
- Python Redis 常用操作
delete(*names) # 根据删除redis中的任意数据类型 exists(name) # 检测redis的name是否存在 keys(pattern='*') # 根据模型获取redis的n ...
- python连接redis、redis字符串操作、hash操作、列表操作、其他通用操作、管道、django中使用redis
今日内容概要 python连接redis redis字符串操作 redis之hash操作 redis之列表操作 redis其他 通用操作,管道 django中使用redis 内容详细 1.python ...
- java、python及jmeter操作redis(接口自动化必备)
redis是nosql数据库之一,其存储结构简单,提供高性能服务,所以在架构中是很常用的. 在做接口自动化测试过程中,有时也会涉及到redis,比如:发送短信验证码,我们做接口自动化测试,如何模拟发送 ...
随机推荐
- docker 系列 - Dock高阶知识点文章汇集
docker 技术已经研究了一段时间, 基本的知识点和使用场景比较清楚了, 还有一些比较高阶的内容未曾尝试, 将来工作中如果能用到, 再深入研究吧. 这篇博文汇总了一些有用的文章链接. ======= ...
- Ext.net 的锁定列要集中放到前面
如题,Ext.net的锁定列要集中放在一起,不然的话,在使用排序的时候,会引起实际排序列错乱比如有A,B,C,D四列,A,C锁定,最终显示为A C | B D,这个时候如果点击B时,发现排序跑到了C上 ...
- AndroidStudio替换空行
(1)在Edit Replace In Path输入框中输入:^\s*\n (\s代表任何空白字符,\S代表任何非空白字符,*代表任意个数,\n匹配换行符) (2)Replace With输入框的值为 ...
- 钉钉C# 使用数据接口要注意的问题
1.钉钉的数据json全部使用的首字母小写的驼峰写法,如果首字母大写,将读取接口失败. 2.钉钉的文档同一个接口可能有simple和非simple两种写法,如果发现数据不全,可以把simple去掉试试 ...
- Dapper.net 输出存储过程实例
1.存储过程名: public static class CampaignTrackingDomainSql { /// <summary> /// proc /// </summa ...
- Java SE之I/O流:知识框架
- 修改输入框placeholder的样式
1. h5页面: //修改placeholder 样式 (chrome,其余类似加前缀) ::-webkit-input-placeholder { color:rgba(21,30,38,0.35) ...
- 今天碰到一个问题,怎么限制用户在固定宽度的input输入框里输入的长度,由此涉猎到了maxlength属性和size属性以及它们的区别。
最开始想首先要强制在一行,另外超出的隐藏.还有一个思路是把value的值的长度和框的长度怎么联系起来,具体怎么联系我也不知道. 在解决另外一个问题的时候,哥发给我的代码里无意中看见input有个max ...
- Navicat for Mysql连接mysql数据库时出现 2003-Can't connect to MySql server on 'localhost'(10061)
一.环境:linux服务器下 二.问题:在windows7下使用Navicat for Mysql连接mysql数据库时出现 2003-Can't connect to MySql server on ...
- [转] 深入理解Batch Normalization批标准化
转自:https://www.cnblogs.com/guoyaohua/p/8724433.html 郭耀华's Blog 欲穷千里目,更上一层楼项目主页:https://github.com/gu ...