如何在Sanic中使用aiohttp ClientSession?

Tom*_*mer 3 python asynchronous python-3.x aiohttp sanic

我试图了解什么是与Sanic一起使用aiohttp的正确方法。

从aiohttp 文档中,我发现以下内容:

不要为每个请求创建会话。每个应用程序很可能需要一个会话来执行所有请求。更复杂的情况可能需要在每个站点上进行一次会话,例如,一个会话用于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)
Run Code Online (Sandbox Code Playgroud)

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

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

我发现的唯一问题是这个,但这无济于事,因为我需要创建自己的类来使用该会话,而不是sanic。
还可以在Sanic文档中找到内容,该文档指出您不应在eventloop之外创建会话。

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

Joh*_*fis 7

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

为此,我们可以使用before_server_start侦听器,该侦听器将允许我们在应用程序提供第一个字节之前创建实例。

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.aiohttp_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)
Run Code Online (Sandbox Code Playgroud)

代码明细:

  • 我们正在创建一个aiohttp.ClientSession作为参数,将Sanic应用程序在开始时创建的循环作为参数传递,从而避免了过程中的陷阱
  • 我们将该会话存储在Sanic中app
  • 最后,我们正在使用此会话来发出请求。