在课堂上使用时关闭aiohttp ClientSession

问题描述 投票:0回答:4

我有以下代码

session = aiohttp.ClientSession()


async def fetch(session, url):
    while True:
        try:
            async with session.get(url) as response:
                assert response.status == 200
                return await response.json()
        except Exception as error:
            print(error)



class FPL():
    async def get_player_summaries(self, player_ids=[], return_json=False):
        tasks = [asyncio.ensure_future(
                fetch(session, API_URLS["player"].format(player_id)))
                for player_id in player_ids]

        player_summaries = await asyncio.gather(*tasks)

        if return_json:
            return player_summaries

        return [PlayerSummary(player_summary)
                for player_summary in player_summaries]

    async def get_points_against(self):
        players = await self.get_players(return_json=True)
        player_ids = [player["id"] for player in players]
        player_summaries = await self.get_player_summaries(
            player_ids, return_json=True)
        points_against = {}

        for player in players:
            try:
                player_summary = next(
                    summary for summary in player_summaries
                    if summary["history"][0]["element"] == player["id"])
            except Exception:
                continue
            player.update(player_summary)
            position = position_converter(player["element_type"]).lower()

            for fixture in player["history"]:
                if fixture["minutes"] == 0:
                    continue

                points = fixture["total_points"]
                opponent = team_converter(fixture["opponent_team"])
                location = "H" if fixture["was_home"] else "A"

                points_against.setdefault(
                    opponent,
                    {
                        "all": {"H": [], "A": []},
                        "goalkeeper": {"H": [], "A": []},
                        "defender": {"H": [], "A": []},
                        "midfielder": {"H": [], "A": []},
                        "forward": {"H": [], "A": []}
                    }
                )

                points_against[opponent]["all"][location].append(points)
                points_against[opponent][position][location].append(points)

        return points_against

像这样使用

from fpl import FPL
import asyncio

loop = asyncio.get_event_loop()
fpl = FPL()

x = loop.run_until_complete(fpl.get_points_against())
print(x)

这工作正常,并且打印了

x
,但伴随着以下警告

Unclosed client session
client_session: <aiohttp.client.ClientSession object at 0x7fa2138111d0>
Unclosed connector
connections: ['[(<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffac48>, 7377.304262674), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe8ee8>, 7377.305252688), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe8fa8>, 7377.306179118), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fc9528>, 7377.306921374), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fc91c8>, 7377.307587193), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fc9d08>, 7377.308546534), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20c030be8>, 7377.324784641), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe8b88>, 7377.325538414), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffa4c8>, 7377.326132111), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fc92e8>, 7377.327035234), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20c030fa8>, 7377.327984252), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe8408>, 7377.328409375), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffa5e8>, 7377.329149849), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe8a08>, 7377.329776115), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffa1c8>, 7377.330400698), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fd3708>, 7377.331131844), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe8be8>, 7377.331974929), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fd3e88>, 7377.332880665), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fd3fa8>, 7377.339996297), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffa168>, 7377.34077951), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fd3768>, 7377.341734826), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fd3dc8>, 7377.342455072), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fc9288>, 7377.343152698), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffa228>, 7377.343844791), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fd3c48>, 7377.344872661), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fd3d08>, 7377.34534166), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffaee8>, 7377.346136623), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fd3408>, 7377.346773908), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffa828>, 7377.347680292), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe8348>, 7377.34843671), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20c0305e8>, 7377.349162388), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fd3f48>, 7377.349909575), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffab88>, 7377.350612879), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffaa68>, 7377.351261815), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffa588>, 7377.352141721), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe8168>, 7377.352916437), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20c0307c8>, 7377.353702472), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffa3a8>, 7377.354645898), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20c030708>, 7377.355418555), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fd32e8>, 7377.356222696), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20c030d08>, 7377.356890307), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20c030828>, 7377.357748581), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fc98e8>, 7377.358468552), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe89a8>, 7377.36431476), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20c0309a8>, 7377.365148168), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20c030648>, 7377.365791136), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffa528>, 7377.36643204), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20c030dc8>, 7377.367176097), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20c0308e8>, 7377.367818125), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fc9708>, 7377.36853057), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20c030ac8>, 7377.369177849), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20c030e88>, 7377.369894806), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffa048>, 7377.370589053), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe8e28>, 7377.371427258), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fc9ee8>, 7377.37224736), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe8588>, 7377.372942966), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fd3048>, 7377.373591994), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe86a8>, 7377.374399274), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffa0a8>, 7377.374866638), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fd3288>, 7377.375751613), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe8528>, 7377.376432785), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fd39a8>, 7377.377390439), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20c2fcd68>, 7377.381260399), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe83a8>, 7377.382196696), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20c030a68>, 7377.382944559), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20c030ee8>, 7377.3833559), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe8468>, 7377.383995208), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffabe8>, 7377.38498033), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fc9c48>, 7377.385649648), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fc9108>, 7377.38617506), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20c52bfa8>, 7377.388227618), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20c52bf48>, 7377.388934452), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe8d08>, 7377.393284709), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe8108>, 7377.394200951), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fc9ca8>, 7377.395036827), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffae28>, 7377.396141727), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fc9b28>, 7377.396889149), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe8888>, 7377.397542457), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffa768>, 7377.398182665), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffaca8>, 7377.398876879), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fc9be8>, 7377.399550454), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffa6a8>, 7377.400299738), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe8288>, 7377.401028687), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20c35a648>, 7377.401664671), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fc9648>, 7377.402413862), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe8828>, 7377.403071713), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fd3228>, 7377.407205263), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fc9d68>, 7377.408117483), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffa288>, 7377.40877989), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20d570be8>, 7377.409435516), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fc96a8>, 7377.409980892), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffa468>, 7377.410663022), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe81c8>, 7377.411396958), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fc9a68>, 7377.412164899), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fc9348>, 7377.412951192), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fd3468>, 7377.413625465), (<aiohttp.client_proto.ResponseHandler object at 0x7fa20c52bee8>, 7377.414277707), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207ffad68>, 7377.414928317), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fe8ac8>, 7377.415578122), (<aiohttp.client_proto.ResponseHandler object at 0x7fa207fd3b88>, 7377.415948294)]']
connector: <aiohttp.connector.TCPConnector object at 0x7fa20d72c710>

FPL
类还有许多其他功能,所有这些功能似乎都工作正常,所以我只能假设会话is已关闭(会话未关闭可能是由于我发出的大量请求(〜570 ),而其他的是 < 30). I've tried changing the class by making the session an argument that is passed to the class, and then closing it after, but that doesn't seem to work either. In the documentation it is mentioned that session context manager usage is not mandatory, but
await session.close()
方法,在这种情况下应该被调用。由于我在类中使用它的方式不起作用,它可能不是实例化
session
的正确方法。

你应该如何在课堂上使用

aiohttp ClientSession

python python-asyncio aiohttp
4个回答
6
投票

如果您发现嵌套上下文管理器不方便,或者您希望在不注入会话的情况下更轻松地使用您的类,您可以将这些方法添加到您的类中

def __del__(self):
    try:
        loop = asyncio.get_event_loop()
        asyncio.create_task(self._close_session())
    except RuntimeError:
        loop = asyncio.new_event_loop()
        loop.run_until_complete(self._close_session())

async def _close_session(self):
    if not self.session.closed:
        await self.session.close()

async def _create_session(self):
    self.session = aiohttp.ClientSession(connector=aiohttp.TCPConnector(limit=self.tcp_connections))

3
投票

无论您是否下课,都没有区别。关闭它

await session.close()

get_points_against
末尾的某个地方。如果由于某种原因它不适合您 – 请使用尽可能少的代码对其进行测试并将其发布在此处。超级简单的事情就像

import asyncio

from aiohttp import ClientSession

session = ClientSession()

async def fetch(session, url):
    async with session.get(url) as r:
        return (await r.read())[:100]


class Getter:
    async def print_data(self):
        urls = ['https://stackoverflow.com', 'https://google.com']
        for result in await asyncio.gather(*[fetch(session, url) for url in urls]):
            print(result)

        await session.close()

loop = asyncio.get_event_loop()
g = Getter()
loop.run_until_complete(g.print_data())

await session.close()
一起工作正常,并发出与您相同的警告 - 没有。


旁注:aiohttp 强烈反对在 coros 之外创建会话。


0
投票

我认为你应该在外部级别使用管理

ClientSession

async def main():
    async with aiohttp.ClientSession() as session:
        fpl = FPL(session)
        x = await fpl.get_points_againts()
        print(x)


class FPL:

    def __init__(self, session):
        self.session = session

    async def get_player_summaries(self, player_ids=[], return_json=False):
        tasks = [asyncio.ensure_future(
                fetch(self.session, API_URLS["player"].format(player_id)))
                for player_id in player_ids]
        # ...

    # ...


if __name__ == '__main__':
    asyncio.run(main)

顺便说一句。查看类似的问题:使用aiohttp嵌套“异步”


0
投票

由于不能保证

__del__
方法将始终被调用,我建议基于 @Jens_Madsen 答案使用以下代码。

import atexit
import aiohttp

class MyClass:
    def __init__(self) -> None:
        self.session = aiohttp.ClientSession()
        atexit.register(self.cleanup)

    def cleanup(self):
        try:
            loop = asyncio.get_event_loop()
            asyncio.create_task(self._cleanup())
        except RuntimeError:
            loop = asyncio.new_event_loop()
            loop.run_until_complete(self._cleanup())

    async def _cleanup(self):
        if not self.session.closed:
            await self.session.close()

通过这种方式,您还可以从

aiohttp.ClientSession
类继承子类并从那里管理多个会话实例。下面是一个例子:

import atexit
import aiohttp

class MySession(aiohttp.ClientSession):
    _sessions = []
    _registered = False

    def __new__(cls, *args, **kwargs):
        if not cls._registered:
            atexit.register(cls.cleanup)
            cls._registered = True

        return super().__new__(cls)

    def __init__(self, name: str='', enable_trace: bool=False, **kwargs) -> None:
        Session._sessions.append(self)
        super().__init__(**kwargs)

    @classmethod
    def cleanup(cls):
        try:
            loop = asyncio.get_event_loop()
            asyncio.create_task(cls._cleanup())
        except RuntimeError:
            loop = asyncio.new_event_loop()
            loop.run_until_complete(cls._cleanup())

    @classmethod
    async def _cleanup(cls):
        for s in cls._sessions:
            if not s.closed:
                await s.close()
© www.soinside.com 2019 - 2024. All rights reserved.