python使用redis_python应用中使用redis的几个思考
使用pipeline来提高性能
应该使用pipeline来将多个请求组合在一起,一次性在发送给服务器,并返回结果。
import redis
from redis.client import Pipeline
from typing import List
connection = redis.StrictRedis(port=16379, decode_responses=True)
pipe: Pipeline = connection.pipeline()
pipe.set(...) #1
pipe.get(...) #2
pipe.sadd(...) #3
result:List = pipe.execute()
上述代码执行后, #1, #2, #3的结果依次保存在数组result中。如果不使用pipeline,上述#1, #2, #3将分为三次网络传输完成,占用3个RTT的时间,使用pipeline将使得这一时间减少到1个RTT时间。
注意pipeline只是将多个命令组合在一起发送给服务器,且结果也一次性返回,但并不意味着这些命令的执行是原子性的。要保证其原子性,应该使用事务。
pipeline也有美中不足的地方,就是你没有办法利用中间结果进行运算。比如如果#2命令依赖于#1的输出结果,那么这两个操作是无法pipeline在一起的。这时应该使用客户端脚本。
使用迭代和batch操作来提高性能
如果你要一次性地操作比如说1B的数据,那么很有可能你不会有这么多内存来存储返回的keys,这种情况下,应该使用scan操作。比如我们要删除redis中的所有以user:开头的key:
import redis
r = redis.StrictRedis(host='localhost')
for key in r.scan_iter("user:*"):
r.delete(key)
这样内存问题解决了,但是有点慢。
如果要一次操作很多数据,比如说100k以上,应该使用批量操作:
import redis
from itertools import izip_longest
r = redis.StrictRedis(host='localhost', port=6379, db=0)
# iterate a list in batches of size n
def batcher(iterable, n):
args = [iter(iterable)] * n
return izip_longest(*args)
# in batches of 500 delete keys matching user:*
for keybatch in batcher(r.scan_iter('user:*'),500):
r.delete(*keybatch)
这段代码来自于Get all keys in Redis database with python,根据作者的测试,使用批量操作(且batch size为500),最高将提高5倍的速度。
需要使用asyncio吗?
由于python的执行是单线程的,所以在python中,一旦涉及到IO操作,我们都尽可能地使用asyncio来完成。但在访问redis时,是否要使用asyncio,要具体分析。一般来说,我们会把redis服务器部署在离客户端很近的地方,甚至可能就在本机,由于RTT很小,而redis本身性能很高,延时很低,因此完全可以不用异步编程模型。毕竟对redis的使用会很频繁,python的asyncio模型中加入这么多请求后,对其调度性能也是一种考验。两相折冲,使用asyncio的性能并不一定高。也许这也是python下没有特别好的asyncio模型的redis客户端的原因。但是,上述结论是基于我们使用redis的场景是高频,小数据量的情况。如果要与redis交换大量数据,显然还是要使用异步,以免因与redis的通信阻塞程序运行。关于这一点,我并没有做测试,也没有找到合适的benchmark文章。不过看到知乎文章aredis —— 一款高效的异步 redis 客户端也有类似的观点。
如何存储复杂的数据结构?
redis通过set/get, hset/hmset/hmget等命令提供了嵌套级别为0~1级的各种操作。但有时候我们需要读写更复杂的数据结构,我们应该如何拓展信息嵌套的层次呢?
首先,可以使用多个数据库来提供第一层的嵌套(或者第一级的名字空间)。这是通过建立连接时指定db索引来实现的:
import redis
r = redis.StrictRedis(host='localhost', port=6379, db=0)
# 通过r发生的操作都写在db=0这个数据库中。
redis数据库通过整数索引,而不是更易理解的字符串名字来标识。因此,在正式的工程中,你应该定义一些常量,通过常量名来区分各个数据库的作用。不同的数据库是允许存在相同的key的。现在,假设我们有一个CRM系统,则相应的用户数据,我们可以分别保存在vendor(供货商)和customer(客户)数据库下。
redis提供了hash, list, set这样的容器,从而提供了另一个级别的嵌套。比如我们的客户数据可能组成如下:
id -> {
name: 'john',
mobile: 13400001234,
orders: [oid1, oid2, ...]
}
这样我们可以直接通过hmset来更改用户的名字、电话等数据。如果要操作他的订单数据呢?当然我们可以这样:
import redis
r = StrictRedis(...)
id = 123456 # id of user 'john'
orders = r.hget(id, orders)
# modify orders
orders.append('1111-1121')
r.hset(id, orders)
但这样操作的效率不高,因为我们只希望给orders增加一笔订单,没有必要把之前的订单数据都取回来(特别是如果用户订单数据很长的话,那就更是浪费)。但是redis并不提供对这一嵌套级别数据的直接操作。
有两个办法来解决这一问题(如何更高效地修改订单数据)。一是使用服务器脚本。或者,我们在key上做文章。比如对每一级嵌套的容器类型(hash, list, set),我们通过给它一个多级的key来将其从内部嵌套中提取出来。以上面的用户订单数据为例,它是一个两层的嵌套,超过了redis命令可以直接运算的最大深度,因此我们可以这样改造存储在redis中的数据:
id -> {
name: 'john',
mobile: 13400001234
...
}
id:orders -> [oid1, oid2, oid3, ...]
# 还可以通过类似的方法将更深层的数据“扁平化”
python使用redis_python应用中使用redis的几个思考相关推荐
- win10下使用python访问vmbox中的redis
了解到redis没有windows的官方支持,所以在vmbox中的ubuntu装了redis#在ubuntu中 #搜索redis相关软件信息 apt-cache search ^redis #不清楚为 ...
- Python数据库(MySQL、MongoDB、Redis)编程
MySQL 数据库系统解决的问题:持久化存储,优化读写,保证数据的有效性 当前使用的数据库,主要分为两类 文档型,如sqlite,就是一个文件,通过对文件的复制完成数据库的复制 服务型,如mysql. ...
- 分布式中使用 Redis 实现 Session 共享(中)
http://blog.jobbole.com/91874/ 原文出处: 焰尾迭 欢迎分享原创到伯乐头条 上一篇介绍了一些redis的安装及使用步骤,本篇开始将介绍redis的实际应用场景,先从最 ...
- Yaml版接口自动化详细讲解(Python + pytest + allure + log + yaml + mysql + redis + 钉钉通知 + Jenkins)
目录 框架介绍 框架结构 框架功能讲解 common # 配置 config.yaml # 公共配置 setting.py # 环境路径存放区域 data # 测试用例数据 Files # ...
- 用python实现阿里云ecs和redis的创建与维护
最近在研究阿里云服务的ecs和云redis产品,通过开发文档了解到,可以通http请求调用api接口实现ecs和云redis等实例的创建.删除.启动.停止.查询.重启等,当然还有很多其它API接口,具 ...
- c#获取对象的唯一标识_在 Java 中利用 redis 实现分布式全局唯一标识服务
作者: 杨高超 juejin.im/post/5a4984265188252b145b643e 获取全局唯一标识的方法介绍 在一个IT系统中,获取一个对象的唯一标识符是一个普遍的需求.在以前的单体应用 ...
- 使用Python,EoN模拟网络中的疾病扩散模型,并结合matplotlib绘图
使用Python,EoN模拟网络中的疾病扩散模型,并结合matplotlib绘图 1. EoN是什么 2. 安装 3. 效果图 4. 源代码 4.1 源码 4.2 源码 参考 写这篇博客源于博友的提问 ...
- 使用Python,OpenCV在视频中进行实时条形码检测
使用Python,OpenCV在视频中进行实时条形码检测 1. 步骤 2. 适用场景及优化 3. 总结 4. 源码 参考 上一篇博客介绍了如何检测和查找图像中的条形码.这篇博客将进行一些优化以检测实时 ...
- python缩进在程序中长度统一且强制使用_Python习题纠错1
February, 1991 0.9.1 2.Python语言的缩进只要统一即可,不一定是4个空格(尽管这是惯例). Python缩进在程序中长度统一且强制使用. 3.IPO:Input Proces ...
最新文章
- pandas mysql主键_使用Autoincrement将Pandas Dataframe插入MySQL表自动生成主键
- GC优化利器 - HBase2.0全链路offheap
- 计算机视觉与深度学习 | 基于Matlab双目视觉之深度估计(视频中人到相机的距离)(附源代码)
- zabbix 安装_Zabbix的WEB安装与配置
- 如何彻底卸载MySQL
- ubuntu scp命令或者用root连接ssh提示:Permission denied, please try again.错误
- DotNetCommon-搜集.neter开发常用的功能
- List集合多线程并发条件下不安全,如何解决?
- zabbix模板_基于zabbix网页配置自定义tomcat监控模板--监控项、触发器
- 内蒙古自治区赤峰市谷歌高清卫星地图下载(百度网盘离线包下载)
- 通信原理、模电——部分英文术语对照表
- 动词ing形式的5种用法_动词ing形式的5种用法
- Unity3D坦克大战(附代码和原理讲解)
- 诺,你们要的Python进阶来咯!我还没见过比这全面的!
- 经济学原理上中国故事2019尔雅满分答案
- icon-font的使用
- 杀戮尖塔java打不开,关于杀戮尖塔闪退和BUG的可能性及官方解决办法
- Jieba分词词性标注以及词性说明
- C专家编程 --- 书中案例汇编与分析(持续更新中)
- 企业内部控制体系建设路径及启示 ——基于某公司内控建设案例研究
热门文章
- CSS面试总结(大致)
- WEB前端学习六 js什么是闭包
- 前端开发中使用mock模拟数据
- JS 原生实现复选框全选反选功能
- oracle 运营维护_oracle运维(持续更新)
- java rmi jrmp_关于Java 中 RMI、JNDI、LDAP、JRMP、JMX、JMS那些事儿(上)看后的一些总结-1...
- vue项目使用mint-ui库
- Sass mixin与extends、%placeholder、function
- 利用ES6-Promise()方法封装原始jsonp实现跨域请求公用方法(告别使用JQuery封装好的jsonp)
- RPNet++:人脸对齐faceAlignment和基于CNN的三维人脸恢复