使用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的几个思考相关推荐

  1. win10下使用python访问vmbox中的redis

    了解到redis没有windows的官方支持,所以在vmbox中的ubuntu装了redis#在ubuntu中 #搜索redis相关软件信息 apt-cache search ^redis #不清楚为 ...

  2. Python数据库(MySQL、MongoDB、Redis)编程

    MySQL 数据库系统解决的问题:持久化存储,优化读写,保证数据的有效性 当前使用的数据库,主要分为两类 文档型,如sqlite,就是一个文件,通过对文件的复制完成数据库的复制 服务型,如mysql. ...

  3. 分布式中使用 Redis 实现 Session 共享(中)

    http://blog.jobbole.com/91874/ 原文出处: 焰尾迭   欢迎分享原创到伯乐头条 上一篇介绍了一些redis的安装及使用步骤,本篇开始将介绍redis的实际应用场景,先从最 ...

  4. Yaml版接口自动化详细讲解(Python + pytest + allure + log + yaml + mysql + redis + 钉钉通知 + Jenkins)

    目录 框架介绍 框架结构 框架功能讲解 common  # 配置 config.yaml  # 公共配置 setting.py  # 环境路径存放区域 data  # 测试用例数据 Files  #  ...

  5. 用python实现阿里云ecs和redis的创建与维护

    最近在研究阿里云服务的ecs和云redis产品,通过开发文档了解到,可以通http请求调用api接口实现ecs和云redis等实例的创建.删除.启动.停止.查询.重启等,当然还有很多其它API接口,具 ...

  6. c#获取对象的唯一标识_在 Java 中利用 redis 实现分布式全局唯一标识服务

    作者: 杨高超 juejin.im/post/5a4984265188252b145b643e 获取全局唯一标识的方法介绍 在一个IT系统中,获取一个对象的唯一标识符是一个普遍的需求.在以前的单体应用 ...

  7. 使用Python,EoN模拟网络中的疾病扩散模型,并结合matplotlib绘图

    使用Python,EoN模拟网络中的疾病扩散模型,并结合matplotlib绘图 1. EoN是什么 2. 安装 3. 效果图 4. 源代码 4.1 源码 4.2 源码 参考 写这篇博客源于博友的提问 ...

  8. 使用Python,OpenCV在视频中进行实时条形码检测

    使用Python,OpenCV在视频中进行实时条形码检测 1. 步骤 2. 适用场景及优化 3. 总结 4. 源码 参考 上一篇博客介绍了如何检测和查找图像中的条形码.这篇博客将进行一些优化以检测实时 ...

  9. python缩进在程序中长度统一且强制使用_Python习题纠错1

    February, 1991 0.9.1 2.Python语言的缩进只要统一即可,不一定是4个空格(尽管这是惯例). Python缩进在程序中长度统一且强制使用. 3.IPO:Input Proces ...

最新文章

  1. pandas mysql主键_使用Autoincrement将Pandas Dataframe插入MySQL表自动生成主键
  2. GC优化利器 - HBase2.0全链路offheap
  3. 计算机视觉与深度学习 | 基于Matlab双目视觉之深度估计(视频中人到相机的距离)(附源代码)
  4. zabbix 安装_Zabbix的WEB安装与配置
  5. 如何彻底卸载MySQL
  6. ubuntu scp命令或者用root连接ssh提示:Permission denied, please try again.错误
  7. DotNetCommon-搜集.neter开发常用的功能
  8. List集合多线程并发条件下不安全,如何解决?
  9. zabbix模板_基于zabbix网页配置自定义tomcat监控模板--监控项、触发器
  10. 内蒙古自治区赤峰市谷歌高清卫星地图下载(百度网盘离线包下载)
  11. 通信原理、模电——部分英文术语对照表
  12. 动词ing形式的5种用法_动词ing形式的5种用法
  13. Unity3D坦克大战(附代码和原理讲解)
  14. 诺,你们要的Python进阶来咯!我还没见过比这全面的!
  15. 经济学原理上中国故事2019尔雅满分答案
  16. icon-font的使用
  17. 杀戮尖塔java打不开,关于杀戮尖塔闪退和BUG的可能性及官方解决办法
  18. Jieba分词词性标注以及词性说明
  19. C专家编程 --- 书中案例汇编与分析(持续更新中)
  20. 企业内部控制体系建设路径及启示 ——基于某公司内控建设案例研究

热门文章

  1. CSS面试总结(大致)
  2. WEB前端学习六 js什么是闭包
  3. 前端开发中使用mock模拟数据
  4. JS 原生实现复选框全选反选功能
  5. oracle 运营维护_oracle运维(持续更新)
  6. java rmi jrmp_关于Java 中 RMI、JNDI、LDAP、JRMP、JMX、JMS那些事儿(上)看后的一些总结-1...
  7. vue项目使用mint-ui库
  8. Sass mixin与extends、%placeholder、function
  9. 利用ES6-Promise()方法封装原始jsonp实现跨域请求公用方法(告别使用JQuery封装好的jsonp)
  10. RPNet++:人脸对齐faceAlignment和基于CNN的三维人脸恢复