Python 请求/aiohttp:关闭响应对象

Python 请求/aiohttp:关闭响应对象,python,python-requests,aiohttp,python-3.7,Python,Python Requests,Aiohttp,Python 3.7,我对在请求和aiohttp中都需要.close()响应对象感到有点困惑。(请注意,这是一个独立于session.close()的实例方法——我指的是响应对象本身。) Response(requests)或ClientResponse(aiohttp)是否需要显式调用.close() 如果不是,那么将响应本身用作上下文管理器的目的是什么?(与session.request('GET','https://www.pastebin.com(下面的“)如果它被隐式关闭,为什么要为此定义两个dunder

我对在
请求和
aiohttp
中都需要
.close()
响应对象感到有点困惑。(请注意,这是一个独立于
session.close()
的实例方法——我指的是响应对象本身。)

  • Response
    requests
    )或
    ClientResponse
    aiohttp
    )是否需要显式调用
    .close()
  • 如果不是,那么将响应本身用作上下文管理器的目的是什么?(
    与session.request('GET','https://www.pastebin.com(下面的“
    )如果它被隐式关闭,为什么要为此定义两个dunder方法,如下所示
一些简单的测试(如下)似乎暗示,当响应在会话上下文管理器中定义时,它们会自动关闭。(它本身在
\uuuuuu exit\uuuu
\uuuuuu\uuu
中调用
self.close()
。但这是会话的关闭,而不是响应对象。)

示例-
请求
示例-
aiohttp

请求
:不需要显式调用
close()
。请求将在完成后自动关闭,因为它基于urlopen(这就是为什么
resp.raw.closed
为True),这是我观看了
session.py
adapters.py之后的简化代码:

from urllib3 import PoolManager
import time
manager = PoolManager(10)
conn = manager.connection_from_host('host1.example.com')
conn2 = manager.connection_from_host('host2.example.com')
res = conn.urlopen(url="http://host1.example.com/",method="get")
print(len(manager.pools))
manager.clear()
print(len(manager.pools))
print(res.closed)

#2
#0
#True
那么,
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
做了什么?它用于清除
PoolManager(self.PoolManager=PoolManager(…)
proxy

# session.py
def __exit__(self, *args): #line 423
    self.close()
def close(self): #line 733
    for v in self.adapters.values():
        v.close()

# adapters.py
# v.close()
def close(self): #line 307
        self.poolmanager.clear()
        for proxy in self.proxy_manager.values():
            proxy.clear()
那么您应该在什么时候使用
close()
,正如注释所说的释放回池的连接,因为
DEFAULT\u POOLSIZE=10
(http/https是独立的)。这意味着,如果您想在一次会话中访问10个以上的网站,您可以选择关闭一些不需要的网站,否则当您有一个以上的会话时,manager将从第一个网站关闭到最新的网站。但实际上您不需要关心这个问题,您可以指定池大小,并且重建连接不会浪费太多时间

aiohttp
aiohttp.ClientSession()正在为所有请求使用一个TCPConnector。当它触发时,
自身连接器将关闭

编辑:
s.request()
设置了来自主机的连接,但未收到响应
wait resp.text()
只能在得到响应后执行,如果您没有执行此步骤(等待响应),您将在没有响应的情况下退出

if connector is None: #line 132
    connector = TCPConnector(loop=loop)
...
self._connector = connector #line 151
# connection timeout
try:
    with CeilTimeout(real_timeout.connect,loop=self._loop):
    assert self._connector is not None
    conn = await self._connector.connect(
        req,
        traces=traces,
        timeout=real_timeout
        )
...
async def close(self) -> None:
        if not self.closed:
            if self._connector is not None and self._connector_owner:
                self._connector.close()
            self._connector = None
...
async def __aexit__(self,
                       ...) -> None:
        await self.close()
这是显示我所说内容的代码

import asyncio
import aiohttp
import time

async def get():
    async with aiohttp.ClientSession() as s:
        # The response is already closed after this `with` block.
        # Why would it need to be used as a context manager?
        resp = await s.request('GET', 'https://www.stackoverflow.com')
        resp2 = await s.request('GET', 'https://www.github.com')
        print("resp:",resp._closed)
        print("resp:",resp._connection)
        print("resp2:",resp2._closed)
        print("resp2:",resp2._connection)
        s.close()
        print(s.closed)
        c = await resp.text()
        d = await resp2.text()

    print()
    print(s._connector)
    print("resp:",resp._closed)
    print("resp:",resp._connection)
    print("resp2:",resp2._closed)
    print("resp2:",resp2._connection)

loop = asyncio.get_event_loop()
loop.run_until_complete(get())  # Python 3.5 +

#dead loop

我的理解是,当脚本完成时,它们会自动关闭。但是通过什么手段呢@kcorlidy我想知道当会话调用
\uuuuu exit\uuuu
\uuuu aexit\uuu
时,
响应本身是如何关闭的。在aiohttp中,当您使用..as退出
时,上下文管理器将触发
\uuu aexit\uu
<代码>\uuuu aexit\uuuu
包含self.close(),它可以关闭
TCPConnector
。您可以查看
aiohttp/client.py
第864 803 150 132行。
请求
更复杂,我发现它使用的是
PoolManager
。并使用
manager.connection\u from_host('xx.com').urlopen(url=”等代码打开urlhttp://xx.com/,method=“get”)
。但我仍然不知道为什么连接完成后会关闭。顺便说一句,当使用…as退出
时,
close()
将迭代每个连接并关闭它(view session.py 733),它将在
urlopen
完成后关闭。只需在注释和打印(x.closed)
上尝试我的代码。有趣的是,池管理器的第一个示例特别有用。在这一点上,我想知道两件事:您提到,“在使用
块执行此
之后,响应已经关闭。为什么需要将其用作上下文管理器?”。但是可以直接从aiohttp客户机文档中看到这样一个示例:其次,在您调用其
.text()
方法之前关闭
resp
是毫无意义的(在会话调用
\uu aexit\uu
之前,仍然在
with
块中)。为什么
resp
会关闭,而
resp2
显示
False
为什么它需要用作上下文管理器?
请求中,上下文管理器将关闭会话,实际上它清除了池管理器(我的第二部分代码显示)。在
aiohttp
中,上下文管理器用于关闭TCPConnector,但
s.request
仅从主机建立连接,请求仍在运行
wait x.text()
只能在收到响应后执行。这就是为什么如果删除
wait x.text()
,您将获得
x.。\u connection->connection
resp.\u connection或resp2.\u connection
将保留,如果在获得响应之前退出。但实际上连接是关闭的@布拉德所罗门
# session.py
def __exit__(self, *args): #line 423
    self.close()
def close(self): #line 733
    for v in self.adapters.values():
        v.close()

# adapters.py
# v.close()
def close(self): #line 307
        self.poolmanager.clear()
        for proxy in self.proxy_manager.values():
            proxy.clear()
if connector is None: #line 132
    connector = TCPConnector(loop=loop)
...
self._connector = connector #line 151
# connection timeout
try:
    with CeilTimeout(real_timeout.connect,loop=self._loop):
    assert self._connector is not None
    conn = await self._connector.connect(
        req,
        traces=traces,
        timeout=real_timeout
        )
...
async def close(self) -> None:
        if not self.closed:
            if self._connector is not None and self._connector_owner:
                self._connector.close()
            self._connector = None
...
async def __aexit__(self,
                       ...) -> None:
        await self.close()
import asyncio
import aiohttp
import time

async def get():
    async with aiohttp.ClientSession() as s:
        # The response is already closed after this `with` block.
        # Why would it need to be used as a context manager?
        resp = await s.request('GET', 'https://www.stackoverflow.com')
        resp2 = await s.request('GET', 'https://www.github.com')
        print("resp:",resp._closed)
        print("resp:",resp._connection)
        print("resp2:",resp2._closed)
        print("resp2:",resp2._connection)
        s.close()
        print(s.closed)
        c = await resp.text()
        d = await resp2.text()

    print()
    print(s._connector)
    print("resp:",resp._closed)
    print("resp:",resp._connection)
    print("resp2:",resp2._closed)
    print("resp2:",resp2._connection)

loop = asyncio.get_event_loop()
loop.run_until_complete(get())  # Python 3.5 +

#dead loop