【问题标题】:python asyncio/aiohttp sharing globals across projectpython asyncio/aiohttp 跨项目共享全局变量
【发布时间】:2018-12-18 21:20:22
【问题描述】:

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

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

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

而且,明智的测试 - 每个模块都应该定义一个全局变量,例如:
loop = asyncio.get_event_loop()
或者,将事件循环传递给模块是否更好,例如在类__init__)?

【问题讨论】:

    标签: python testing pytest python-asyncio aiohttp


    【解决方案1】:

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

    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()
    

    这有几个优点:

    • 它不需要任何全局状态;
    • 您可以完全控制状态的构建和拆除位置(一次完成);
    • 如果您决定需要并行完成多个全局操作,这样做很容易 - 只需创建多个 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() 获得,当从协程调用时,可以保证返回当前正在运行的循环。

    【讨论】:

    • 我仍然不知道如何跨模块共享这些。如果一个模块需要访问读取器,写入器。主要应该将操作对象传递给它吗?如果模块需要 http 会话,则相同
    • @user3599803 你会像在 python 中的其他东西一样分享这些。模块中的代码通常以函数和类的形式组织。这些类只能在__init__ 中接收一次操作(随意选择更好的名称),并且模块级函数可以简单地接受它们实际需要的参数(不一定是整个操作)。全局状态的缺点之一是你永远不知道谁在使用什么。
    • 它与模块全局变量有何不同?因为这样的类应该是我项目中的一个单例。我也看不到客户端会话的异步使用 - 我看到在这种情况下不可能使用?
    • 重点是它并不需要是一个单例(在单例模式的意义上),你选择它是这样的。就像aiohttp.ClientSession:它可以实现为全局,但它可以让您更好地控制它。至于async with,只要你正确关闭会话,这应该无关紧要。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-10
    • 2017-08-19
    • 2019-01-15
    • 2013-03-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多