python - Tornado 应用程序中的 asyncio.lock

标签 python locking tornado python-asyncio

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

经过几个小时的实验,我发现了一些事情,

  1. 如果锁 block 中没有await,一切都按预期工作
  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 不起作用。

最佳答案

Tornado 和 asyncio 都有一个全局单例事件循环,其他一切都依赖于它(对于高级用例,您可以避免单例,但使用它是惯用的)。要一起使用这两个库,两个单例需要相互了解。

AsyncIOMainLoop().install() 创建一个指向 asyncio 单例的 Tornado 事件循环,然后将其设置为 Tornado 单例。这行得通。

IOLoop.configure('AsyncIOLoop') 告诉 Tornado“每当你需要 IOLoop 时,创建一个新的(非单例!)asyncio 事件循环并使用它。asyncio 循环成为单例时IOLoop 已启动。这几乎 有效,但是当定义了 MainHandler 类(并创建其类范围的 asyncio.Lock 时,asyncio singleton 仍然指向默认值(它将被 AsyncIOLoop 创建的那个取代)。

TL;DR:使用 AsyncIOMainLoop,而不是 AsyncIOLoop,除非您尝试使用更高级的非单例使用模式。这在 Tornado 5.0 中会变得更简单,因为异步集成将默认启用。

关于python - Tornado 应用程序中的 asyncio.lock,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46479019/

相关文章:

python - tornado python 的简单异步示例

python - 如何正确导入不同包.proto文件中的protobuf消息?

python - 使用 python 匹配 fasta 文件中的 header

c++ - 以线程安全的方式与外界共享一个数据成员

java - 为什么 await of Condition 会释放锁而 signal 不会?

url - url路径与用斜杠关闭的路径有明显区别吗?

django - 在 Heroku 上部署 Django\Tornado

python - 减少函数中变量的正确方法是什么?

python - 没有 'class object' 的 getattr()

java - 如何禁用JPA的锁系统?