首页 文章

如何在Sanic中使用aiohttp ClientSession?

提问于
浏览
2

我试图了解在Sanic中使用aiohttp的正确方法是什么 .

从aiohttp documentation,我发现以下内容:

不要为每个请求创建会话 . 最有可能的是,每个应用程序都需要一个会话来完成所有请求 . 更复杂的情况可能需要每个站点的会话,例如,一个用于Github,另一个用于Facebook API . 无论如何,为每个请求进行会话是一个非常糟糕的主意 . 会话内部包含连接池 . 连接重用和保持活动(两者都默认打开)可以加快总体性能 .

当我去Sanic文档时,我找到了一个这样的例子:

这是一个例子:

from sanic import Sanic
from sanic.response import json

import asyncio
import aiohttp

app = Sanic(__name__)

sem = None

@app.route("/")
async def test(request):
    """
    Download and serve example JSON
    """
    url = "https://api.github.com/repos/channelcat/sanic"

    async with aiohttp.ClientSession() as session:
         async with sem, session.get(url) as response:
         return await response.json()

app.run(host="0.0.0.0", port=8000, workers=2)

这不是管理aiohttp会话的正确方法......

那么正确的方法是什么?
我应该在应用程序中初始化会话并将会话注入所有层中的所有方法吗?

我找到的唯一问题是this但这没有用,因为我需要创建自己的类来使用会话,而不是sanic .
在Sanic文档中也找到了this,它说你不应该在eventloop之外创建一个会话 .

我有点困惑:(什么是正确的方法?

2 回答

  • 2

    为了使用单个 aiohttp.ClientSession ,我们只需要实例化一次会话,并在应用程序的其余部分中使用该特定实例 .

    为了实现这一点,我们可以使用before_server_start listener,这将允许我们在应用程序提供第一个字节之前创建实例 .

    from sanic import Sanic 
    from sanic.response import json
    
    import aiohttp
    
    app = Sanic(__name__)
    
    @app.listener('before_server_start')
    def init(app, loop):
        app.aiohttp_session = aiohttp.ClientSession(loop=loop)
    
    @app.listener('after_server_stop')
    def finish(app, loop):
        loop.run_until_complete(app.session.close())
        loop.close()
    
    @app.route("/")
    async def test(request):
        """
        Download and serve example JSON
        """
        url = "https://api.github.com/repos/channelcat/sanic"
    
        async with app.aiohttp_session.get(url) as response:
            return await response.json()
    
    
    app.run(host="0.0.0.0", port=8000, workers=2)
    

    Breakdown of the code:

    • 我们正在创建一个 aiohttp.ClientSession ,将 Sanic apps在开始时创建的循环作为参数传递,避免在此过程中使用this pitfall .

    • 我们将该会话存储在Sanic app 中 .

    • 最后,我们正在使用此会话来提出请求 .

  • 1

    这基本上就是我在做的事情 .

    我创建了一个模块( interactions.py ),例如具有如下函数:

    async def get(url, headers=None, **kwargs):
        async with aiohttp.ClientSession() as session:
            log.debug(f'Fetching {url}')
            async with session.get(url, headers=headers, ssl=ssl) as response:
                try:
                    return await response.json()
                except Exception as e:
                    log.error(f'Unable to complete interaction: {e}')
                    return await response.text()
    

    那我就是 await

    results = await interactions.get(url)
    

    我不确定为什么这不是“正确的方式” . 我的请求完成后,会话(至少根据我的需要)可以关闭 .

相关问题