我正在尝试编写一个异步方法,以便在Tornado应用程序中使用。我的方法需要管理一个连接,该连接可以并且应该在对函数的其他调用之间共享,该函数是由await
ing创建的。为了管理这个问题,我使用了asyncio.Lock
。但是,每次调用我的方法都会挂起等待锁。在
经过几个小时的试验,我发现了一些东西
await
s,则一切正常tornado.ioloop.IOLoop.configure('tornado.platform.asyncio.AsyncIOLoop')
无济于事tornado.platform.asyncio.AsyncIOMainLoop().install()
允许它工作,不管事件循环是以tornado.ioloop.IOLoop.current().start()
还是asyncio.get_event_loop().run_forever()
开始的以下是一些示例代码,除非您取消注释AsyncIOMainLoop().install()
,否则这些代码将无法工作:
import tornado.ioloop
import tornado.web
import tornado.gen
import tornado.httpclient
from tornado.platform.asyncio import AsyncIOMainLoop
import asyncio
import tornado.locks
class MainHandler(tornado.web.RequestHandler):
_lock = asyncio.Lock()
#_lock = tornado.locks.Lock()
async def get(self):
print("in get")
r = await tornado.gen.multi([self.foo(str(i)) for i in range(2)])
self.write('\n'.join(r))
async def foo(self, i):
print("Getting first lock on " + i)
async with self._lock:
print("Got first lock on " + i)
# Do something sensitive that awaits
await asyncio.sleep(0)
print("Unlocked on " + i)
# Do some work
print("Work on " + i)
await asyncio.sleep(0)
print("Getting second lock on " + i)
async with self._lock:
print("Got second lock on " + i)
# Do something sensitive that doesnt await
pass
print("Unlocked on " + i)
return "done"
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
#AsyncIOMainLoop().install() # This will make it work
#tornado.ioloop.IOLoop.configure('tornado.platform.asyncio.AsyncIOLoop') # Does not help
app = make_app()
app.listen(8888)
print('starting app')
tornado.ioloop.IOLoop.current().start()
我现在知道了tornado.locks.Lock()
存在并且工作,但是我很好奇asyncio.Lock
为什么不工作。在
Tornado和asyncio都有一个全局单例事件循环,其他一切都依赖于它(对于高级用例,您可以避免使用singleton,但使用它是惯用的)。要同时使用这两个库,这两个单例需要相互了解。在
AsyncIOMainLoop().install()
生成一个Tornado事件循环,该循环指向asyncio singleton,然后将其设置为Tornado singleton。这很管用。在IOLoop.configure('AsyncIOLoop')
告诉Tornado“无论何时需要IOLoop,都要创建一个新的(非单例!)异步事件循环并使用它。启动IOLoop时,asyncio循环成为单例。这个几乎可以工作,但是当MainHandler
类被定义(并创建其类作用域asyncio.Lock
)时,asyncio单例仍然指向默认值(将由AsyncIOLoop创建的类替换)。在TL;DR:使用AsyncIOMainLoop,而不是asyncialoop,除非您试图使用更高级的非单例使用模式。这在Tornado5.0中会变得更简单,因为默认情况下会启用异步集成。在
相关问题 更多 >
编程相关推荐