异步锁在Tornado应用程序中

2024-05-06 11:01:58 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试编写一个异步方法,以便在Tornado应用程序中使用。我的方法需要管理一个连接,该连接可以并且应该在对函数的其他调用之间共享,该函数是由awaiting创建的。为了管理这个问题,我使用了asyncio.Lock。但是,每次调用我的方法都会挂起等待锁。在

经过几个小时的试验,我发现了一些东西

  1. 如果锁块中没有awaits,则一切正常
  2. tornado.ioloop.IOLoop.configure('tornado.platform.asyncio.AsyncIOLoop')无济于事
  3. 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为什么不工作。在


Tags: importselfasynciolockappasynconawait
1条回答
网友
1楼 · 发布于 2024-05-06 11:01:58

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中会变得更简单,因为默认情况下会启用异步集成。在

相关问题 更多 >