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 coro

    asyncio的情况下为
    run_tasks()
    实现这三个属性的建议。如果您指定了关键字param
    return_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时,这可能会导致问题。关键是着眼于未来,而不是
    循环的结果