代码之家  ›  专栏  ›  技术社区  ›  Tamás Szelei

如何管理单个aiohttp.ClientSession?

  •  5
  • Tamás Szelei  · 技术社区  · 6 年前

    import aiohttp
    import asyncio
    
    async def fetch(session, url):
      async with session.get(url) as response:
        return await response.text()
    
    async def main(url, session):
      print(f"Starting '{url}'")
      html = await fetch(session, url)
      print(f"'{url}' done")
    
    urls = (
      "https://python.org",
      "https://twitter.com",
      "https://tumblr.com",
      "https://example.com",
      "https://github.com",
    )
    
    loop = asyncio.get_event_loop()
    session = aiohttp.ClientSession()
    loop.run_until_complete(asyncio.gather(
      *(loop.create_task(main(url, session)) for url in urls)
    ))
    # session.close()   <- this doesn't make a difference
    

    但是,在协同程序之外创建ClientSession显然不是一条路:

    ➜ python 1_async.py
    1_async.py:30: UserWarning: Creating a client session outside of coroutine is a very dangerous idea
      session = aiohttp.ClientSession()
    Creating a client session outside of coroutine
    client_session: 
    Starting 'https://python.org'
    Starting 'https://twitter.com'
    Starting 'https://tumblr.com'
    Starting 'https://example.com'
    Starting 'https://github.com'
    'https://twitter.com' done
    'https://example.com' done
    'https://github.com' done
    'https://python.org' done
    'https://tumblr.com' done
    1_async.py:34: RuntimeWarning: coroutine 'ClientSession.close' was never awaited
      session.close()
    Unclosed client session
    client_session: 
    Unclosed connector
    connections: ['[(, 15024.110107067)]', '[(, 15024.147785039)]', '[(, 15024.252375415)]', '[(, 15024.292646968)]', '[(, 15024.342368087)]', '[(, 15024.466971983)]', '[(, 15024.602057745)]', '[(, 15024.837045568)]']
    connector: 
    

    FWIW,这是 main

    async def main(url):
      async with aiohttp.ClientSession() as session:
        print(f"Starting '{url}'")
        html = await fetch(session, url)
        print(f"'{url}' done")
    

    正确的方法是什么?我考虑过将一个url列表传递给main,但无法使其以非顺序方式工作。

    1 回复  |  直到 6 年前
        1
  •  6
  •   Sraw    6 年前

    Creating a client session outside of coroutine is a very dangerous idea 因为当您创建它时,它被绑定到当前循环。如果你在之后改变跑步循环,它将挂起。但如果你足够小心地使用它,你可以忽略它。 Related doc .

    至于我,我只是忽略了这个警告。但也很容易克服:

    async def create_session():
        return aiohttp.ClientSession()
    
    session = asyncio.get_event_loop().run_until_complete(create_session())
    

    此外,您不需要显式地创建 Task 对象,但只执行此协程函数:

    loop.run_until_complete(asyncio.gather(
      *(main(url, session) for url in urls)
    ))
    

    最后,别忘了 close 是一次联程旅行。你应该用 loop.run_until_complete(session.close()) 结束 session .

    顺便说一句,如果您想创建一个类似异步的循环,可以参考 my another answer