Python asyncio在保留顺序和处理错误的同时运行多个任务
我的函数Python asyncio在保留顺序和处理错误的同时运行多个任务,python,python-3.x,python-asyncio,Python,Python 3.x,Python Asyncio,我的函数运行任务(所有任务,窗口大小)接受任务生成器并返回其值,同时: 同时从所有任务运行每个窗口(大小为窗口大小) 保留返回结果的顺序(所有任务[i]结果为结果[i]) 处理每次运行的异常 我目前的执行情况: import asyncio from itertools import islice # run all tasks and return their results in the same order # window is the max number of tasks tha
运行任务(所有任务,窗口大小)
接受任务生成器并返回其值,同时:
所有任务运行每个窗口(大小为窗口大小
)
所有任务[i]
结果为结果[i]
)import asyncio
from itertools import islice
# run all tasks and return their results in the same order
# window is the max number of tasks that will run in parallel
def run_tasks(all_tasks, window_size=4):
loop = asyncio.get_event_loop()
while True:
window_tasks = list(islice(all_tasks, window_size))
if not window_tasks:
break
futures = asyncio.wait(window_tasks, loop=loop)
finished, unfinished = loop.run_until_complete(futures)
# sort finished tasks by their launch order.
# removing this line makes returned tasks unordered
finished = sorted(finished, key=lambda f: window_tasks.index(f._coro))
for finished_task in finished:
try:
yield finished_task.result()
except Exception as e:
yield repr(e)
# Example Usage:
# a coroutine that sometime raises exception
async def sleepy(i):
print(f'{i} started')
await asyncio.sleep(10 - i)
print(f'{i} finished')
if i == 5:
raise ValueError('5 is the worst')
return i
# a generator of tasks
all_tasks = (sleepy(i) for i in range(10))
for result in list(run_tasks(all_tasks)):
print(result)
问题
我的实现的问题是,如果不访问f.\u coro
这是asyncio.Task
对象的内部属性,我就无法找到一种方法来对任务进行排序
# removing this line makes returned tasks unordered
finished = sorted(finished, key=lambda f: window_tasks.index(f._coro))
我可以使用asyncio.gather(*tasks)
,但这不会处理错误
我愿意听取关于如何在不访问
f.\u coroasyncio的情况下为run_tasks()
实现这三个属性的建议。如果您指定了关键字paramreturn_exceptions
,则gather
将返回错误。要将实际异常与协同路由返回的异常对象区分开来,您可以使用确保未来将窗口中的任务
与任务包装在一起:
futures = [asyncio.ensure_future(t, loop=loop) for t in window_tasks]
gathered = asyncio.gather(*futures, loop=loop, return_exceptions=True)
loop.run_until_complete(gathered)
for fut in futures:
try:
yield fut.result()
except Exception as e:
yield repr(e)
谢谢,我确实注意到了return\u exceptions
参数,但是您无法区分它返回的异常,但是您无法区分它返回的异常
-您可以。试试我贴的代码。我们只需要返回\u异常
而不需要通过asyncio.gather
引发异常。但我们不检查收集的
结果,我们检查我们创建的
期货的结果。他们将在fut.result()
上返回正常的协同路由结果,如果在协同路由中引发异常,则调用并引发异常。是的,这是正确的,我测试了它,它正常工作。我刚刚注意到,我尝试使用return\u异常并尝试查看结果,但正如您所注意到的,当返回值的类型为exception时,这可能会导致问题。关键是着眼于未来,而不是循环的结果