我正在编写一个类,它将使用aiohttp进行http请求。根据文档,我不应该为每个请求创建一个ClientSession,所以我想重用同一会话。
代码:
public void CreateUniqueBuyList(List<EveObjModel> buyList)
{
//sort by ascending type_id and then by ascending price and reverse it. so that,
// object with higher price come first
List<EveObjModel>tempList = buyList.OrderBy(x => x.type_id).ThenBy(x => x.price).Reverse().ToList();
List<EveObjModel> uniqueBuyList = new List<EveObjModel>();
for (int i = 0; i < tempList.Count; ++i) {
if ((i > 1) && tempList[i - 1].type_id == tempList[i].type_id) continue; // if duplicate type_id then don't take it again
uniqueBuyList.Add(tempList[i]);
}
foreach (EveObjModel item in uniqueBuyList.OrderBy(item => item.type_id))
{
buyListtextField.Text += $"Eve Online Item! Type-ID is: {item.type_id}, Price is {item.price}\n";
}
}
这样做的时候
class TestApi:
def __init__(self):
self.session = aiohttp.ClientSession()
# async defs methods from here
我得到错误:TestApi()
。
持久保存Unclosed client session
对象的解决方案是什么?
答案 0 :(得分:2)
一行上的表达式TestApi()
本身会创建一个TestApi
对象,并立即将其丢弃。 aiohttp
抱怨该会话从未关闭过(退出async with
块或显式调用close()
),但即使没有警告,也不要不分配将API对象指向实际使用该变量的变量。
要重用该会话,您的代码需要有权访问该会话或拥有它的对象:
async def fetch(url):
async with aiohttp.request('GET', url) as resp:
resp.raise_for_status()
return await resp.read()
async def main():
url1_data, url2_data = asyncio.gather(
fetch('http://url1', fetch('http://url2'))
url3_data, url4_data = asyncio.gather(
fetch('http://url3', fetch('http://url4'))
一种选择是将session
参数添加到fetch
(和其他函数)中,并用在main()
中创建的会话一致地调用它。更好的选择是创建一个API类,并将fetch
之类的全局函数转换为方法:
class Http:
async def __aenter__(self):
self._session = aiohttp.ClientSession()
return self
async def __aexit__(self, *err):
await self._session.close()
self._session = None
async def fetch(self, url):
async with self._session.get(url) as resp:
resp.raise_for_status()
return await resp.read()
main()
仍然可以作为一个函数存在,但是可以一致地使用持有会话的对象:
async def main():
async with Http() as http:
url1_data, url2_data = await asyncio.gather(
http.fetch('http://url1', http.fetch('http://url2'))
url3_data, url4_data = await asyncio.gather(
http.fetch('http://url3', http.fetch('http://url4'))
在上面的代码中,async with
语句用于确保只要保留作用域就关闭会话。
答案 1 :(得分:0)
实际上,我看不到您的代码有什么根本错误。
除了,当TestApi对象被破坏时(可能在程序完成时),您将需要调用 close 函数。否则,您会收到此警告。
(这是一个协程,需要等待:https://docs.aiohttp.org/en/stable/client_reference.html)