如何异步使用Tornado和Redis?
我正在尝试了解如何异步使用Redis和Tornado。我找到了tornado-redis这个库,但我需要的不仅仅是在代码中加一个yield
。
我有以下代码:
import redis
import tornado.web
class WaiterHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def get(self):
client = redis.StrictRedis(port=6279)
pubsub = client.pubsub()
pubsub.subscribe('test_channel')
for item in pubsub.listen():
if item['type'] == 'message':
print item['channel']
print item['data']
self.write(item['data'])
self.finish()
class GetHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello world")
application = tornado.web.Application([
(r"/", GetHandler),
(r"/wait", WaiterHandler),
])
if __name__ == '__main__':
application.listen(8888)
print 'running'
tornado.ioloop.IOLoop.instance().start()
我需要访问/
这个网址,并在/wait
有请求等待时获取“Hello World”。我该怎么做呢?
4 个回答
4
对于Python版本3.3及以上,我建议你使用aioredis这个库。下面的代码我没有测试过,但应该是类似这样的:
import redis
import tornado.web
from tornado.web import RequestHandler
import aioredis
import asyncio
from aioredis.pubsub import Receiver
class WaiterHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def get(self):
client = await aioredis.create_redis((host, 6279), encoding="utf-8", loop=IOLoop.instance().asyncio_loop)
ch = redis.channels['test_channel']
result = None
while await ch.wait_message():
item = await ch.get()
if item['type'] == 'message':
print item['channel']
print item['data']
result = item['data']
self.write(result)
self.finish()
class GetHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello world")
application = tornado.web.Application([
(r"/", GetHandler),
(r"/wait", WaiterHandler),
])
if __name__ == '__main__':
print 'running'
tornado.ioloop.IOLoop.configure('tornado.platform.asyncio.AsyncIOLoop')
server = tornado.httpserver.HTTPServer(application)
server.bind(8888)
# zero means creating as many processes as there are cores.
server.start(0)
tornado.ioloop.IOLoop.instance().start()
5
你需要使用与Tornado IOLoop兼容的Redis客户端。
现在有几个这样的客户端可供选择,比如toredis和brukva等。
这里有一个使用toredis的发布/订阅示例:https://github.com/mrjoes/toredis/blob/master/tests/test_handler.py
7
你不应该在Tornado的主线程中使用Redis的发布/订阅功能,因为这样会阻塞输入输出循环。你可以在主线程中处理来自网页客户端的长轮询,但应该为监听Redis创建一个单独的线程。然后,你可以使用 ioloop.add_callback()
和/或 threading.Queue
来与主线程进行沟通,当你收到消息时就可以通知主线程。