python asyncio / aiohttp在整个项目中共享全局变量

时间:2018-12-18 21:20:22

标签: python testing pytest python-asyncio aiohttp

我有一个asyncio项目。它有几个模块。他们中的许多人需要访问一些全局变量,例如: 1. aiohttp ClientSession()对象,因为根据aiohttp文档,我应该避免为每个请求创建一个新的ClientSession。
2.异步套接字,即我使用reader, writer创建的asyncio.open_connection()。我想保持持久的连接。
3.事件循环,我使用asyncio.get_event_loop()

共享此类变量的最佳实践是什么?
我想创建一个globals.py模块,它将定义这些变量。

问题是我无法在globals模块中为async with对象使用ClientSession语法。
  对于套接字,我必须在异步def中以某种方式定义它,所以我不能在模块级别公开它。

并且,明智地进行测试-每个模块都应定义一个全局变量,例如:
 loop = asyncio.get_event_loop()
或者,最好将事件循环传递给模块,例如在类__init__中)?

1 个答案:

答案 0 :(得分:0)

没有必要使用全局变量。而是,创建一个存储“全局”数据的类,并在该类上使用function方法。例如:

class Operation:
    def __init__(self):
        self._http = aiohttp.ClientSession()

    async def open(self):
        self._reader, self._writer = \
            await asyncio.open_connection(<host>, <port>)

    # ... more methods ...

    async def close(self):
        await self._http.close()
        self._writer.close()
        await self._writer.wait_closed()

这有几个优点:

  • 不需要任何全局状态; <​​/ li>
  • 您可以完全控制状态的构造和拆除位置(全部一次);
  • 如果您决定需要并行执行多个全局操作,那么这样做很容易-只需创建多个Operation实例即可。
  • 进行测试时,您只需根据需要创建和拆除Operation实例。

在适当的位置,您的main协程应如下所示:

async def main():
    op = Operation()
    await op.open()
    try:
        await op.do_something()
        ...
    finally:
        await op.close()

asyncio.run(main())
#or asyncio.get_event_loop().run_until_complete(main())

请注意,事件循环存储在对象上或以任何方式传递给对象。这是因为始终可以使用asyncio.get_event_loop()获得事件循环,当从协程调用该事件循环时,可以保证返回当前正在运行的循环。