【问题标题】:asyncio.lock in a Tornado applicationTornado 应用程序中的 asyncio.lock
【发布时间】:2017-09-28 22:09:01
【问题描述】:

我正在尝试编写用于 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 无效。

【问题讨论】:

    标签: python locking tornado python-asyncio


    【解决方案1】:

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

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

    IOLoop.configure('AsyncIOLoop') 告诉 Tornado “只要你需要一个 IOLoop,就创建一个新的(非单例!)异步事件循环并使用它。当 IOLoop 启动时,异步循环成为单例。这几乎 em> 有效,但是当定义 MainHandler 类时(并创建其类范围的 asyncio.Lock,asyncio 单例仍指向默​​认值(将被 AsyncIOLoop 创建的替换)。

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

    【讨论】:

      猜你喜欢
      • 2012-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多