aioredis - asyncio (PEP 3156) Redis support
aioredisはasyncioを使ってredisとのやりとりを行うためのパッケージです。
redisがボトルネックになるような環境ではもしかしたら使えるかも?と思ったので試してみます。
Python3が対象です。
PyPI: https://pypi.python.org/pypi/aioredis
Document: http://aioredis.readthedocs.org/en/latest/
インストール
いつものアレです。
$ pip install aioredis
DEPRECATION: --download-cache has been deprecated and will be removed in the future. Pip now automatically uses and configures its cache.
Collecting aioredis
Downloading aioredis-0.2.2-py3-none-any.whl
Collecting hiredis (from aioredis)
Downloading hiredis-0.2.0.tar.gz (46kB)
100% |################################| 49kB 3.7MB/s
Installing collected packages: hiredis, aioredis
Running setup.py install for hiredis
building 'hiredis_for_hiredis_py' library
clang -Wno-unused-result -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -c vendor/hiredis/read.c -o build/temp.macosx-10.10-x86_64-3.4/vendor/hiredis/read.o
clang -Wno-unused-result -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -c vendor/hiredis/sds.c -o build/temp.macosx-10.10-x86_64-3.4/vendor/hiredis/sds.o
ar rc build/temp.macosx-10.10-x86_64-3.4/libhiredis_for_hiredis_py.a build/temp.macosx-10.10-x86_64-3.4/vendor/hiredis/read.o build/temp.macosx-10.10-x86_64-3.4/vendor/hiredis/sds.o
ranlib build/temp.macosx-10.10-x86_64-3.4/libhiredis_for_hiredis_py.a
building 'hiredis.hiredis' extension
〜省略〜
Successfully installed aioredis-0.2.2 hiredis-0.2.0
特に何も問題なくすんなり入りました。
サンプルコードを試してみる
ではサンプルコードを試してみます。
redis-serverを起動しておいてくださいね。
Simple low-level interface
READMEのものをそのままコピペです。
import asyncio
import aioredis
loop = asyncio.get_event_loop()
@asyncio.coroutine
def go():
conn = yield from aioredis.create_connection(
('localhost', 6379), loop=loop)
yield from conn.execute('set', 'my-key', 'value')
val = yield from conn.execute('get', 'my-key')
print(val)
conn.close()
loop.run_until_complete(go())
aioredis.create_connection()でコネクションオブジェクトを生成しています。
実行してみます。
$ python simple.py
b'value'
redis-cli monitor
で見ているとちゃんと設定されていることがわかります。
1437429410.490170 [0 [::1]:60100] "SET" "my-key" "value"
1437429410.490412 [0 [::1]:60100] "GET" "my-key"
Simple high-level interface:
こちらもREADMEのものをそのままコピペです。
import asyncio
import aioredis
loop = asyncio.get_event_loop()
@asyncio.coroutine
def go():
redis = yield from aioredis.create_redis(
('localhost', 6379), loop=loop)
yield from redis.set('my-key', 'value')
val = yield from redis.get('my-key')
print(val)
redis.close()
loop.run_until_complete(go())
# will print 'value'
違いはlow-levelのものがaioredis.create_connection()でコネクションオブジェクトを生成していたのに対し、high-levelではaioredis.create_redis()でredisのコマンドのwrapper関数を実装したオブジェクトを生成しています。
そのため、execute()で実行するのではなく、get()メソッドとset()メソッドで値の保存と取得をしています。
では実行してみます。
$ python high-level.py
b'value'
1437429812.921592 [0 [::1]:60140] "SET" "my-key" "value"
1437429812.921852 [0 [::1]:60140] "GET" "my-key"
先ほどと同じ結果が得られました。
redis-cli monitorも同様に出力されています。
コネクションプール
コネクションプールも面倒見てくれそうです。
こちらもREADMEのコピペです。
import asyncio
import aioredis
loop = asyncio.get_event_loop()
@asyncio.coroutine
def go():
pool = yield from aioredis.create_pool(
('localhost', 6379),
minsize=5, maxsize=10,
loop=loop)
with (yield from pool) as redis: # high-level redis API instance
yield from redis.set('my-key', 'value')
print((yield from redis.get('my-key')))
pool.clear() # closing all open connections
loop.run_until_complete(go())
ここでは aioredis.create_pool()でコネクションプールの管理オブジェクトを作成し、
それにevent_loopを渡しています。
では実行してみます。
$ python connection-pool.py
b'value'
Task was destroyed but it is pending!
task: <Task pending coro=<_read_data() running at /Users/sximada/ng/var/lib/virtualenv/py3k/lib/python3.4/site-packages/aioredis/connection.py:104> wait_for=<Future pending cb=[Task._wakeup()]> cb=[Future.set_result()]>
Task was destroyed but it is pending!
task: <Task pending coro=<_read_data() running at /Users/sximada/ng/var/lib/virtualenv/py3k/lib/python3.4/site-packages/aioredis/connection.py:104> wait_for=<Future pending cb=[Task._wakeup()]> cb=[Future.set_result()]>
Task was destroyed but it is pending!
task: <Task pending coro=<_read_data() running at /Users/sximada/ng/var/lib/virtualenv/py3k/lib/python3.4/site-packages/aioredis/connection.py:104> wait_for=<Future pending cb=[Task._wakeup()]> cb=[Future.set_result()]>
Task was destroyed but it is pending!
task: <Task pending coro=<_read_data() running at /Users/sximada/ng/var/lib/virtualenv/py3k/lib/python3.4/site-packages/aioredis/connection.py:104> wait_for=<Future pending cb=[Task._wakeup()]> cb=[Future.set_result()]>
Task was destroyed but it is pending!
task: <Task pending coro=<_read_data() running at /Users/sximada/ng/var/lib/virtualenv/py3k/lib/python3.4/site-packages/aioredis/connection.py:104> wait_for=<Future pending cb=[Task._wakeup()]> cb=[Future.set_result()]>
(py3k)
1437430657.702979 [0 [::1]:60332] "SELECT" "0"
1437430657.704267 [0 [::1]:60333] "SELECT" "0"
1437430657.705696 [0 [::1]:60334] "SELECT" "0"
1437430657.706967 [0 [::1]:60335] "SELECT" "0"
1437430657.708267 [0 [::1]:60336] "SELECT" "0"
1437430657.708580 [0 [::1]:60332] "SET" "my-key" "value"
1437430657.708821 [0 [::1]:60332] "GET" "my-key"