【发布时间】:2020-10-10 01:45:39
【问题描述】:
我正在尝试同时向一个 url (~50) 发送许多请求。
from asyncio import Queue
import yaml
import asyncio
from aiohttp import ClientSession, TCPConnector
async def http_get(url, cookie):
cookie = cookie.split('; ')
cookie1 = cookie[0].split('=')
cookie2 = cookie[1].split('=')
cookies = {
cookie1[0]: cookie1[1],
cookie2[0]: cookie2[1]
}
async with ClientSession(cookies=cookies) as session:
async with session.get(url, ssl=False) as response:
return await response.json()
class FetchUtil:
def __init__(self):
self.config = yaml.safe_load(open('../config.yaml'))
def fetch(self):
asyncio.run(self.extract_objects())
async def http_get_objects(self, object_type, limit, offset):
path = '/path' + \
'?query=&filter=%s&limit=%s&offset=%s' % (
object_type,
limit,
offset)
return await self.http_get_domain(path)
async def http_get_objects_limit(self, object_type, offset):
result = await self.http_get_objects(
object_type,
self.config['object_limit'],
offset
)
return result['result']
async def http_get_domain(self, path):
return await http_get(
f'https://{self.config["domain"]}{path}',
self.config['cookie']
)
async def call_objects(self, object_type, offset):
result = await self.http_get_objects_limit(
object_type,
offset
)
return result
async def extract_objects(self):
calls = []
object_count = (await self.http_get_objects(
'PV', '1', '0'))['result']['count']
for i in range(0, object_count, self.config['object_limit']):
calls.append(self.call_objects('PV', str(i)))
queue = Queue()
for i in range(0, len(calls), self.config['call_limit']):
results = await asyncio.gather(*calls[i:self.config['call_limit']])
await queue.put(results)
使用 fetch 作为入口点运行此代码后,我收到以下错误消息:
/usr/local/Cellar/python/3.7.4_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/events.py:88: RuntimeWarning: coroutine 'FetchUtil.call_objects' was never awaited
self._context.run(self._callback, *self._args)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
在asyncio.gather第一次返回后停止执行的程序。我很难理解这条消息,因为我认为我努力确保所有功能都是异步任务。我没有await 的唯一功能是call_objects,因为我希望它同时运行。
https://xinhuang.github.io/posts/2017-07-31-common-mistakes-using-python3-asyncio.html#org630d301
在这篇文章中给出如下解释:
此运行时警告可能在许多情况下发生,但原因是 相同:通过调用异步创建协程对象 函数,但从未插入到 EventLoop 中。
当我使用 asyncio.gather 调用异步任务时,我相信这就是我正在做的事情。
我应该注意,当我在 http_get 中放置 print('url') 时,它会输出我想要的前 50 个 url,当 asyncio.gather 第一次返回时似乎会出现问题。
【问题讨论】:
-
也许
[i:self.config['call_limit']]应该是[i:i + self.config['call_limit']]?前者可能会产生一堆空切片,这导致一些调用永远不会传递给gather(因此从未等待)。 -
您发现了一个我修复的逻辑错误,然后我的程序开始按预期工作,所以谢谢,但我实际上不明白为什么它不只是多次执行相同的请求而不是停止出现错误。
-
我现在已经发布了解释作为答案。
标签: python-3.x python-asyncio aiohttp