我正在 Python 中迈出第一步,我在尝试理解为什么我没有得到预期的结果时遇到了一些困难。这是我想要实现的目标:
我有一个使用 API 的函数。在等待 API 响应并考虑到我正在通过一个会产生额外延迟的代理时,我认为发送并发请求会加快进程(我运行 100 个并发请求)。确实如此。但是 asyncio run_until_complete
总是返回一些未完成的协程。
这里的代码(简化):
import aiohttp
import asyncio
async def consume_api(parameter):
url = "someurl" #it is actually based on the parameter
try:
async with aiohttp.ClientSession() as session:
async with session.get(URL, proxy="someproxy") as asyncresponse:
r = await asyncresponse.read()
except:
global error_count
error_count += 1
if error_count > 50:
return "Exceeded 50 try on same request"
else:
return consume_api(parameter)
return r.decode("utf-8")
def loop_on_api(list_of_parameter):
loop = asyncio.get_event_loop()
coroutines = [consume_api(list_of_parameter[i]) for i in range(len(list_of_parameter))]
results = loop.run_until_complete(asyncio.gather(*coroutines))
return results
当我运行调试器时,results
函数返回的 loop_on_api
包括与 consume_api
的结果相对应的字符串列表和 <coroutine objects consume_api at 0x00...>
的一些出现。这些变量在 False 和 cr_Frame 处有一个 cr_running 参数。
虽然如果我检查 coroutines
变量,我可以找到所有 100 个协程,但似乎没有一个具有 cr_Frame。
知道我做错了什么吗?
我也在考虑我计算 50 错误的方法将被所有协程共享。
知道如何使其具体化吗?
答案 0 :(得分:0)
问题似乎来自我使用的代理,它有时不携带请求或响应。因此,强制重新运行似乎是最好的答案。因此,我现在检查返回的结果是否还有一些协程,并在它们上重新运行 loop_on_api()
def loop_on_api(list_of_parameter):
loop = asyncio.get_event_loop()
coroutines = [consume_api(list_of_parameter[i]) for i in range(len(list_of_parameter))]
results = loop.run_until_complete(asyncio.gather(*coroutines))
undone = []
rerun_list_of_parameter = []
for i in range(len(results)):
if str(type(results[i])) == "<class 'coroutine'>": #not very elegant >> is there a better way?
undone.append(i)
rerun_list_of_parameter.append(list_of_parameter[i])
if len(undone) > 0:
undone_results = loop_on_api(rerun_list_of_parameter)
for i in range(len(undone_results)):
results[undone[i]] = undone_results[i]
return results
答案 1 :(得分:0)
这应该可行,您可以添加/更改/重构您想要的任何内容
import aiohttp
import asyncio
async def consume_api(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.read()
def loop_on_api(list_of_urls):
loop = asyncio.get_event_loop()
coroutines = [consume_api(url) for url in list_of_urls]
results = loop.run_until_complete(asyncio.gather(*coroutines))
return results
if __name__ == '__main__':
print(loop_on_api(['https://google.com', 'https://twitter.com']))