Tags : Ajax  apache  awk  besttrace  bootstrap  CDN  Django  git 

常见问题

Python包:redis-py说明

stevezhou      2014.09.25   


下载地址:https://pypi.python.org/pypi/redis/  

redis简单示例

-----------------------------------------

>>> import redis
>>> r=redis.StrictRedis(host='localhost',port=6379,db=0)
>>> r.set('foo','bar')

True

>>> r.get('foo')

'bar'

 

API 参考

------------------------------------------------------------------------------------------------------------------

redis命令官方参考文档<http://redis.io/commands>,上面有对每个redis命令的详细说明。redis-py包提供了实现这些命令的两个客户端类。StrictRedis试图遵照redis本身的命令语法。但也有以下几点改动:

* **SELECT**:未实现该命令。

* **DEL**:redis中的命令'del'更名为'delete'。

* **CONFIG GET|SET**:分别用方法 config_get 与 config_set实现。

* **MULTI/EXEC**:事务被作为Pipeline类的一部分实现。默认情况下,pipeline执行方式类似 MULTI与EXEC,可以通过设置transaction=False禁用它。详细见下面的Pipelines说明。

* **SUBSCRIBE/LISTEN**:类似pipeline, 由于需要下层的连接保持状态, PubSub 也实现成单独的类。调用 Redis 客户的 pubsub 方法返回一个 PubSub 的实例,通过这个实例可以订阅频道或侦听消息。两个类(StrictRedis 和 PubSub 类)都可以发布(PUBLISH)消息。

除了上面的改变,StrictRedis 的子类 Redis,提供了对旧版本 redis-py 的兼容:

* **LREM**:‘num'与 'value’参数的位置调换,'num'参数的默认值 为0。

* **ZADD**:参数位置调换了,参数位置如: 'name1,score1,name2,score2,...'。

* **SETEX**:'time'与'value'的参数位置调换。

原译者注解因此不要用 Redis,这个类只是做兼容用的

 

连接池

^^^^^^^^^^^^^^^^^^^^^

***********************************

补充知识点:连接池操作

1)建立数据库连接池对象(服务器启动);

2)按照事先指定的参数创建初始数量的数据库连接(即:空闲连接数);

3)对于一个数据库访问请求,直接从连接池中得到一个连接。如果数据库连接池对象中没有空闲的连接,且连接数没有达到最大(即:最大活跃连接数),创建一个新的数据库连接;

4)存取数据库;

5)关闭数据库,释放所有数据库连接(此时的关闭数据库连接,并非真正关闭,而是将其放空闲中。如实际空闲连接数大于初始空闲连接数则释放连接)。

6)释放数据库连接池对象(服务器停止、维护期间,释放数据库连接池对象,并释放所有连接)

***********************************

redis-py用连接池方式管理到redis服务器的连接。默认情况下,每个Redis实例都会有属于自己的连接池。你也可以用已经存在的连接池实例作为一个Redis类的参数来改变这种方式。以更高效地利用连接池。

>>> pool=redis.ConnectionPool(host='localhost',port=6379,db=0)
>>> r=redis.Redis(connection_pool=pool)

 

连接

^^^^^^^^^^^^^^^^^

ConnectionPool 管理一组 Connection 实例。redis-py 提供两种类型的 Connection。缺省情况下,Connection 是一个普通的 TCP 连接。 UnixDomainSocketConnection 允许和服务器运行在同一个设备上的客户端通过 unix 套接字进行连接。要使用 UnixDomainSocketConnection 连接, 只需要通过unix_socket_path 参数传递一个 unix 套接字文件的字符串。另外,确保redis.conf 文件配置了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 中就有,可以自己下载安装。

 

响应回调函数

^^^^^^^^^^^^^^^^

客户端类使用一系列回调函数来把 Redis 响应转换成合适的 Python 类型。有些回调函数在 Redis 客户端类的字典 RESPONSE_CALLBACKS 中定义。

通过 set_response_callback 方法可以把自定义的回调函数添加到单个实例。这个方法接受两个参数:一个命令名和一个回调函数。通过这种方法添加的回调函数只对添加到的对象有效。要想全局定义或重载一个回调函数,应该创建 Redis 客户端的子类并把回调函数添加到类的 RESPONSE_CALLBACKS(原文误为REDIS_CALLBACKS) 中。

响应回调函数至少有一个参数:Redis 服务器的响应。要进一步控制如何解释响应,也可以使用关键字参数。这些关键字参数在对 execute_command 的命令调用时指定。通过 “withscores” 参数,ZRANGE 演示了回调函数如何使用关键字参数。

 

线程安全

^^^^^^^^^^^^^^^^

Redis 客户端实例可以安全地在线程间共享。从内部实现来说,只有在命令执行时才获取连接实例,完成后直接返回连接池,命令永不修改客户端实例的状态。

但是,有一点需要注意:SELECT 命令。SELECT 命令允许切换当前连接使用的数据库。新的数据库保持被选中状态,直到选中另一个数据库或连接关闭。这会导致在返回连接池时,连接可能指定了别的数据库。

因此,redis-py 没有在客户端实例中实现 SELECT 命令。如果要在同一个应用中使用多个 Redis 数据库,应该给第一个数据库创建独立的客户端实例(可能也需要独立的连接池)。

在线程间传递 PubSub 和 Pipeline 对象是不安全的。

 

Pipeline

^^^^^^^^^^^^^^^^

Pipelines是Redis类的子类,支持单个请求中缓存多条命令。它极大的了命令执行的效率,减少了客户端与服务器间的请求、响应次数。Pipelines的使用很简单:

>>> r=redis.Redis()
>>> p=r.pipeline()
>>> p.set('bing','baz')
>>> p.set('age','27')
>>> p.get('age')
>>> p.get('bing')
>>> p.execute()

[True, True, '27', 'baz']

为了方便使用,所有缓冲到 pipeline 的命令返回 pipeline 对象本身。所以,也可以这样写:

p=r.pipeline()
p.set('bing','baz').set('age','27')get('age')get('bing').execute()

pipeline里面缓冲的命令组默认具有原子性,若要禁止这种原子性,可以关闭 transaction

p=r.pipeline(transaction=False)

一个常见的问题是:在进行原子事务操作前需要从 Redis 中获取事务中要用的数据。比如,假设 INCR 命令不存在,但我们需要用 Python 创建一个原子版本的 INCR。

一个不成熟的实现是获取值(GET),在 Python 中增一, 设置(SET)新值。但是,这不是原子操作,因为多个客户端可能在同一时间做这件事,每一个都通过 GET 获取同一个值。

WATCH 命令提供了在开始事务前监视一个或多个键的能力。如果这些键中的任何一个在执行事务前发生改变,整个事务就会被取消并抛出 WatchError 异常。要实现我们的客户 INCR 命令,可以按下面的方法操作:

>>> with r.pipeline() as pipe:

...     while 1:

...         try:

...             # 对序列号的键进行 WATCH

...             pipe.watch('OUR-SEQUENCE-KEY')

...             # WATCH 执行后,pipeline 被设置成立即执行模式直到我们通知它
...             # 重新开始缓冲命令。
...             # 这就允许我们获取序列号的值

...             current_value = pipe.get('OUR-SEQUENCE-KEY')

...             next_value = current_value + 1

...             # 现在我们可以用 MULTI 命令把 pipeline 设置成缓冲模式

...             pipe.multi()

...             pipe.set('OUR-SEQUENCE-KEY', next_value)

...             # 最后,执行 pipeline (set 命令)

...             pipe.execute()

...             # 如果执行时没有抛出 WatchError,我们刚才所做的确实“原子地”
...             # 完成了

...             break

...         except WatchError:

...             # 一定是其它客户端在我们开始 WATCH 和执行 pipeline 之间修改了
...             # 'OUR-SEQUENCE-KEY',我们最好的选择是重试

...             continue

 

注意,因为在整个 WATCH 过程中,Pipeline 必须绑定到一个连接,必须调用 reset() 方法确保连接返回连接池。如果 Pipeline 用作 Context Manager(如上面的例子所示), reset() 会自动调用。当然,也可以用手动的方式明确调用 reset():

>>> pipe = r.pipeline()

>>> while 1:

...     try:

...         pipe.watch('OUR-SEQUENCE-KEY')

...         ...

...         pipe.execute()

...         break

...     except WatchError:

...         continue

...     finally:

...         pipe.reset()

 

重点(原译者注):

·WATCH 执行后,pipeline 被设置成立即执行模式

·用 MULTI 命令把 pipeline 设置成缓冲模式

·要么使用 with,要么调用 reset()

有一个方便的transaction的方法来处理这种情形并重新监视错误。它的参数是一个可执行对象(一般 为一个函数)和要 WATCH 任意个数的键,其中可执行对象接受一个 pipeline 对象做为参数。上面的客户端 INCR 命令可以重写如下(更可读):

>>> def client_side_incr(pipe):

...     current_value = pipe.get('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')

说明:transaction的原型为,transaction(self, func, *watches, **kwargs)

 

译文地址:http://blog.sina.com.cn/s/blog_6262a50e0101574h.html



标签 :  python包 上一篇     下一篇