I'm trying to write a asynchronous method for use in a Tornado application. My method needs to manage a connection that can and should be shared among other calls to the function The connection is created by awaiting. To manage this, I was using asyncio.Lock. However, every call to my method would hang waiting for the lock.
After a few hours of experimenting, I found out a few things,
- If nothing
awaits in the lock block, everything works as expected tornado.ioloop.IOLoop.configure('tornado.platform.asyncio.AsyncIOLoop')does not helptornado.platform.asyncio.AsyncIOMainLoop().install()allows it to work, regardless if the event loop is started withtornado.ioloop.IOLoop.current().start()orasyncio.get_event_loop().run_forever()
Here is some sample code that wont work until unless you uncomment 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()
I now know that tornado.locks.Lock() exists and works, but I'm curious why the asyncio.Lock does not work.