Python 3.x 龙卷风&x2B;为什么我的redis呼叫被阻塞了?
我尝试在Tornado和Redis的基础上构建一个具有两个API端点的简单系统:Python 3.x 龙卷风&x2B;为什么我的redis呼叫被阻塞了?,python-3.x,redis,async-await,tornado,python-asyncio,Python 3.x,Redis,Async Await,Tornado,Python Asyncio,我尝试在Tornado和Redis的基础上构建一个具有两个API端点的简单系统: 从Redis读取值或等待该值存在的API(使用BRPOP:value=yield from Redis.BRPOP(“测试”)) 编写此值的API(使用LPUSH:redis.LPUSH(“测试”、“值”)) 所以我希望能够以任何顺序调用这些API。事实上,如果我叫2。然后1.,它按预期工作,调用1。立即返回值 问题是,如果我打1。然后2.,两个请求都阻止永不返回 同时,当请求阻塞时,我仍然可以直接在Redis中L
BRPOP
:value=yield from Redis.BRPOP(“测试”)
)LPUSH
:redis.LPUSH(“测试”、“值”)
)LPUSH
/BRPOP
,甚至可以使用相同的键。类似地,我可以在Tornado中调用其他处理程序。所以我猜这个街区既不在Redis也不在Tornado,而是在我使用aioredis的时候?也许是异步IO循环?但我不明白我错在哪里。有小费吗
谢谢你的帮助
这是我的密码:
import tornado.ioloop
import tornado.web
from tornado import web, gen
from tornado.options import options, define
import aioredis
import asyncio
class WaitValueHandler(tornado.web.RequestHandler):
@asyncio.coroutine
def get(self):
redis = self.application.redis
value = yield from redis.brpop("test")
self.write("I received a value: %s" % value)
class WriteValueHandler(tornado.web.RequestHandler):
@asyncio.coroutine
def get(self):
redis = self.application.redis
res = yield from redis.lpush("test", "here is the value")
self.write("Ok ")
class Application(tornado.web.Application):
def __init__(self):
tornado.ioloop.IOLoop.configure('tornado.platform.asyncio.AsyncIOMainLoop')
handlers = [
(r"/get", WaitValueHandler),
(r"/put", WriteValueHandler)
]
super().__init__(handlers, debug=True)
def init_with_loop(self, loop):
self.redis = loop.run_until_complete(
aioredis.create_redis(('localhost', 6379), loop=loop)
)
if __name__ == "__main__":
application = Application()
application.listen(8888)
loop = asyncio.get_event_loop()
application.init_with_loop(loop)
loop.run_forever()
好吧,我知道为什么了:
共享模式下的阻塞操作(如blpop、brpop或长时间运行的LUA脚本)将阻塞连接,从而可能导致整个程序故障
通过对此类操作使用独占连接,可以轻松解决此阻塞问题:
redis = await aioredis.create_redis_pool(
('localhost', 6379),
minsize=1,
maxsize=1)
async def task():
# Exclusive mode
with await redis as r:
await r.set('key', 'val')
asyncio.ensure_future(task())
asyncio.ensure_future(task())
# Both tasks will first acquire connection.