管道
python
管道是Redis的子類,它支持緩衝多個命令,一次性發送到服務器去執行。能夠大大的提升性能,減小服務器到客戶端之間的TCP來回數據包。
web
管道的簡單使用:redis
>>> r = redis.Redis(...) >>> r.set('bing', 'baz') >>> # Use the pipeline() method to create a pipeline instance >>> pipe = r.pipeline() >>> # The following SET commands are buffered >>> pipe.set('foo', 'bar') >>> pipe.get('bing') >>> # the EXECUTE call sends all buffered commands to the server, returning >>> # a list of responses, one for each command. >>> pipe.execute() [True, 'baz']
For ease of use, all commands being buffered into the pipeline return the pipeline object itself. Therefore calls can be chained like:服務器
爲了便於使用,能夠像下面這樣寫。
app
>>> pipe.set('foo', 'bar').sadd('faz', 'baz').incr('auto_number').execute() [True, True, 6]
In addition, pipelines can also ensure the buffered commands are executed atomically as a group. This happens by default. If you want to disable the atomic nature of a pipeline but still want to buffer commands, you can turn off transactions.ide
此外,管道還能夠確保緩衝命令做爲一組去執行。默認就是這樣(就是管道開啓了事務)。性能
要是想禁用原子性質的管道,還想緩衝命令,像下面這樣設置。
ui
>>> pipe = r.pipeline(transaction=False)
A common issue occurs when requiring atomic transactions but needing to retrieve values in Redis prior for use within the transaction. For instance, let's assume that the INCR command didn't exist and we need to build an atomic version of INCR in Python.this
一個常見的問題:有些狀況下須要先得到一條命令的返回值,而後在執行這個值的下一條命令,而事物中只有當全部命令都一次執行完成後才能獲得每一個結果的返回值。例如,假設INCR命令不存在,咱們在python中實現帶有原子性質的INCR命令。
atom
The completely naive implementation could GET the value, increment it in Python, and SET the new value back. However, this is not atomic because multiple clients could be doing this at the same time, each getting the same value from GET.
經過GET獲取key存在的值,而後經過SET設置新的值,但這不是原子性質的。同一時間多個客戶端能夠這麼操做,每一個均可以使用GET獲取相同的值。
Enter the WATCH command. WATCH provides the ability to monitor one or more keys prior to starting a transaction. If any of those keys change prior the execution of that transaction, the entire transaction will be canceled and a WatchError will be raised. To implement our own client-side INCR command, we could do something like this:
WATCH命令。WATCH能夠監視一個或多個key在開啓事務以前。若是被監視的key在事務執行以前被修改過了,接下來的事務操做會被拒絕執行。實現咱們本身客戶端的INCR命令,能夠像下面這樣:
>>> with r.pipeline() as pipe: ... while 1: ... try: ... pipe.watch('OUR-SEQUENCE-KEY') #監視的key ... current_value = pipe.get('OUR-SEQUENCE-KEY')#獲取存在的key值 ... next_value = int(current_value) + 1#計算 ... pipe.multi()#開啓事務 ... pipe.set('OUR-SEQUENCE-KEY', next_value)#設置key值 ... pipe.execute()#執行 .... break#執行成功退出循環 ... except WatchError: .... continue#若是監視的值被別的客戶端動了,會引起錯誤,但咱們還得繼續執行 #由於咱們還沒讓key的值改變,直到修改了key的值,才結束
Note that, because the Pipeline must bind to a single connection for the duration of a WATCH, care must be taken to ensure that the connection is returned to the connection pool by calling the reset() method. If the Pipeline is used as a context manager (as in the example above) reset() will be called automatically. Of course you can do this the manual way by explicity calling reset():
注意:由於管道在執行WATCH期間綁定到一個鏈接,經過調用reset()方法確保鏈接被放回到鏈接池。
若是管道只做爲命令緩衝,reset方法會自動被調用,你能夠手動調用復位。
>>> pipe = r.pipeline() >>> while 1: ... try: ... pipe.watch('OUR-SEQUENCE-KEY') ... ... pipe.execute() ... break ... except WatchError: ... continue ... finally: ... pipe.reset()
A convenience method named "transaction" exists for handling all the boilerplate of handling and retrying watch errors. It takes a callable that should expect a single parameter, a pipeline object, and any number of keys to be WATCHed. Our client-side INCR command above can be written like this, which is much easier to read:
存在一個名爲transaction的便利方法,能夠處理上面的狀況,嘗試下看看狀況。
有一個可調用參數-管道對象,或者其餘的須要WATCH監視的key.
咱們的客戶端INCR命令能夠寫成下面這樣,更簡單和易讀。
>>> def client_side_incr(pipe): ... current_value = pipe.get('OUR-SEQUENCE-KEY') ... next_value = int(current_value) + 1 ... pipe.multi() ... pipe.set('OUR-SEQUENCE-KEY', next_value) >>> >>> r.transaction(client_side_incr, 'OUR-SEQUENCE-KEY') [True]