pythonredis模块官⽅⽂档(上)
redis-py提供两个类Redis和StrictRedis⽤于实现Redis的命令,StrictRedis⽤于实现⼤部分官⽅的命令,并使⽤官⽅的语法和命令(⽐如,SET命令对应与StrictRedis.set⽅法)。Redis是StrictRedis的⼦类,⽤于向后兼容旧版本的redis-py。
StrictRedis:
select#没有实现,参见下⾯线程安全⼩节
del#与python的del冲突,⽤delete代替
CONFIG GET|SET#config_get config_set
MULTI/EXEC#被当做Pipeline的⼀部分,执⾏时默认被 MULTI 和EXEC状态包裹,可以⽤transaction=False 关闭SUBSCRIBE/LISTEN#和Pipeline类似,PubSub作为单独的类实现,它⽣成潜在的连接状态,此时⽆法执⾏⾮pubsub命令,在redis-client端执⾏PubSub会返回⼀个pubsub实例,可以⽤它来订阅频道,监听信息,注意只能在client端执⾏
SCAN/SSCAN/HSCAN/ZSCAN#*scan命令在redis⽂件中实现,每个⽅法都有⼀个迭代器⽅法,这样纯粹时为了⽅便⽤户,不⽤记录迭代器的游标,⽤scan_iter/sscan_iter/hscan_iter/zscan_iter实现
StrictRedis的⼦类Redis重写了⼀些⽅法实现了后向兼容
LREM#num和value顺序颠倒了,以便num可以提供缺省值0
ZADD#在value前指明score,实现时意外交换了顺序,⼈们已经使⽤时才发现,Redis期望*args格式是name1, score1, name2, score2, …SETEX#time和value的顺序颠倒
redis使⽤连接池管理与redis-server的连接,默认每个redis实例会创建⾃⼰的连接池,可以⽤已经存在的连接池覆盖实例redis的connection_pool参数来覆盖这⼀⾏为,你可以通过这种⽅式实现客户端的切分或连接池的管理
>>> pool = redis.ConnectionPool(host='localhost', port=6379, db=0)
>>> r = redis.Redis(connection_pool=pool)
ConnectionPools管理着连接实例的集合,redis实线两种类型的连接,默认使⽤基于tcp socket的连接,
UnixDomainSocketConnection 允许和服务器运⾏在同⼀个设备上的客户端通过 unix 套接字进⾏连接。要使
⽤ UnixDomainSocketConnection 连接, 只需要通过unix_socket_path 参数传递⼀个 unix 套接字⽂件的字符串。另外,确
保f ⽂件配置了unixsocket 参数(缺省情况下是注释掉的):
>>> r = redis.Redis(unix_socket_path='/tmp/redis.sock')
也可以⾃⼰创建 Connection ⼦类。这个特性可以在使⽤异步框架时⽤于控制 socket 的⾏为。要使⽤⾃⼰的Connection 初始化客户端类,需要创建⼀个连接池,通 connection_class 参数把⾃⼰的类传递进去。传递的其它关键字参数会在初始化时传递给⾃定义的类:
>>> pool = redis.ConnectionPool(connection_class=YourConnectionClass,
your_arg='...', ...)
解析器
解析类提供了控制如何对 Redis 服务器的响应进⾏解析的途径。redis-py 提供了两个解析类, PythonParser和 HiredisParser。缺省情况下,如果安装了 hiredis 模块, redis-py 会尝试使⽤ HiredisParser,否则使⽤ PythonParser。
Hiredis 是由 Redis 核⼼团队维护的 C 库。 Pieter Noordhuis 创建了 Python 的实现。分析 Redis 服务器的响应时,Hiredis 可以提
供 10 倍的速度提升。性能提升在获取⼤量数据时优为明显,⽐如 LRANGE 和SMEMBERS 操作。
和 redis-py ⼀样,Hiredis 在 Pypi 中就有,可以通过 pip 或 easy_install 安装:
$ pip install hiredis
或:
$ easy_install hiredis
响应回调函数
客户端类使⽤⼀系列回调函数来把 Redis 响应转换成合适的 Python 类型。很多回调函数在 Redis 客户端类的字
典 RESPONSE_CALLBACKS 中定义。
通过 set_response_callback ⽅法可以把⾃定义的回调函数添加到单个实例。这个⽅法接受两个参数:
⼀个命令名和⼀个回调函数。通过这种⽅法添加的回调函数只对添加到的对象有效。要想全局定义或重载⼀个回调函数,应该创建 Redis 客户端的⼦类并把回调函数添加到类的 RESPONSE_CALLBACKS
响应回调函数⾄少有⼀个参数:Redis 服务器的响应。要进⼀步控制如何解释响应,也可以使⽤关键字参数。这些关键字参数在
对 execute_command 的命令调⽤时指定。通过 “withscores” 参数,ZRANGE 演⽰了回调函数如何使⽤关键字参数。python官方文档中文版
线程安全
Redis 客户端实例可以安全地在线程间共享。从内部实现来说,只有在命令执⾏时才获取连接实例,完成后直接返回连接池,命令永不修改客户端实例的状态。
但是,有⼀点需要注意:SELECT 命令。SELECT 命令允许切换当前连接使⽤的数据库。新的数据库保持被选中状态,直到选中另⼀个数据库或连接关闭。这会导致在返回连接池时,连接可能指定了别的数据库。
因此,redis-py 没有在客户端实例中实现 SELECT 命令。如果要在同⼀个应⽤中使⽤多个 Redis 数据
库,应该给第⼀个数据库创建独⽴的客户端实例(可能也需要独⽴的连接池)。
在线程间传递 PubSub 和 Pipeline 对象是不安全的。
Pipeline
Pipeline 是 Redis 基类的⼀个⼦类,⽀持在⼀个请求⾥发送缓冲的多个命令。通过减少客户端和服务器之间往来的数据包,可以⼤⼤提⾼命令组的性能。
Pipeline 的使⽤⾮常简单:
>>> r = redis.Redis(...)
>>> r.set('bing', 'baz')
>>> # 使⽤ pipeline()⽅法创建 pipeline 对象
>>> pip3 = r.pipeline()
>>> # 下⾯的set⽅法被缓存
>>> pipe.set('foo', 'bar')
>>> ('bing')
>>> # 调⽤execute发送所有缓存命令到服务器端,并返回响应的list,每个命令对应着list的⼀项
>>> ute()
[True, 'baz']
为了⽅便使⽤,所有缓冲到 pipeline 的命令返回 pipeline 对象本⾝。因此调⽤可以链式连接:
>>> pipe.set('foo', 'bar').sadd('faz', 'baz').incr('auto_number').execute()
[True, True, 6]
另外,pipeline 也可以保证缓冲的命令组做为⼀个原⼦操作。缺省就是这种模式。要使⽤命令缓冲,但禁⽌pipeline 的原⼦操作属性,可以关掉 transaction:
>>> pipe = r.pipeline(transaction=False)
⼀个常见的问题是:在进⾏原⼦事务操作前需要从 Redis 中获取事务中要⽤的数据。⽐如,假设 INCR 命令不存在,但我们需要
⽤ Python 创建⼀个原⼦版本的 INCR。
⼀个不成熟做法是先获取值(GET),在 Python 中加1, 设置(SET)新值。但是,这不是原⼦操作,因为多个客户端可能在同⼀时间做这件事,每⼀个都通过 GET 获取同⼀个值。
WATCH 命令提供了在开始事务前监视⼀个或多个键的能⼒。如果这些键中的任何⼀个在执⾏事务前发⽣改变,整个事务就会被取消并抛出 WatchError 异常。要实现我们的客户 INCR 命令,可以按下⾯的⽅法操作:
>>> with r.pipeline() as pipe:
... while 1:
... try:
... # 对序列号的键进⾏ WATCH
... pipe.watch('OUR-SEQUENCE-KEY')
... # WATCH 执⾏后,pipeline 被设置成⽴即执⾏模式直到我们通知它
.
.. # 重新开始缓冲命令。
... # 这就允许我们获取序列号的值
... current_value = ('OUR-SEQUENCE-KEY')
... next_value = current_value + 1
... # 现在我们可以⽤ MULTI 命令把 pipeline 设置成缓冲模式
... pipe.multi()
... pipe.set('OUR-SEQUENCE-KEY', next_value)
... # 最后,执⾏ pipeline (set 命令)
... ute()
... # 如果执⾏时没有抛出 WatchError,我们刚才所做的确实“原⼦地”
... # 完成了
.
.. break
... except WatchError:
... # ⼀定是其它客户端在我们开始 WATCH 和执⾏ pipeline 之间修改了
... # 'OUR-SEQUENCE-KEY',我们最好的选择是重试
... continue
注意,因为在整个 WATCH 过程中,Pipeline 必须绑定到⼀个单连接,必须调⽤ reset() ⽅法确保连接返回连接池。如果 Pipeline ⽤作上下⽂管理器(如上⾯的例⼦所⽰,with r.pipeline() as pipe:), reset() 会⾃动调⽤。当然,也可以⽤⼿动的⽅式明确调⽤ reset():
>>> pipe = r.pipeline()
>>> while 1:
... try:
... pipe.watch('OUR-SEQUENCE-KEY')
... ...
... ute()
... break
... except WatchError:
... continue
... finally:
... set()
注:·WATCH 执⾏后,pipeline 被设置成⽴即执⾏模式
·⽤ MULTI 命令把 pipeline 设置成缓冲模式
存在⼀种⽅便的⽅法“transaction”⽤来处理WatchError的处理和重试的模式。它调⽤含有⼀个参数的可执⾏对象,⼀个管道对象,和任意数量要 WATCH的键,其中可执⾏对象接受⼀个 pipeline 对象做为参数。上⾯的客户端 INCR 命令可以重写如下(更易可读):
>>> def client_side_incr(pipe):
... current_value = ('OUR-SEQUENCE-KEY')
... next_value = current_value + 1
... pipe.multi()
... pipe.set('OUR-SEQUENCE-KEY', next_value)
>>> r.transaction(client_side_incr, 'OUR-SEQUENCE-KEY')
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论