Повторите задачу после исключения задачи с помощью asyncio.wait

1

У меня есть несколько сопрограмм, которые должны запускаться одновременно, некоторые из которых могут вызывать исключение. В этих случаях сопрограммы должны запускаться снова. Как это сделать? Минимальная демонстрация того, что я пытаюсь сделать:

import asyncio
import time

t = time.time()


async def c1():
    print("finished c1 {}".format(time.time() - t))


async def c2():
    await asyncio.sleep(3)
    print("finished c2 {}".format(time.time() - t))


called = False


async def c3():
    global called
    # raises an exception the first time it called
    if not called:
        called = True
        raise RuntimeError("c3 called the first time")
    print("finished c3 {}".format(time.time() - t))


async def run():
    pending = {c1(), c2(), c3()}

    num_times_called = 0
    while pending:
        num_times_called += 1
        print("{} times called with {} pending tasks: {}".format(num_times_called, len(pending), pending))

        finished, pending = await asyncio.wait(pending, return_when=asyncio.FIRST_EXCEPTION)
        for task in finished:
            if task.exception():
                print("{} got an exception {}, retrying".format(task, task.exception()))
                pending.add(task)

        print("finished {}".format(finished))

    print("finished all {}".format(time.time() - t))


asyncio.get_event_loop().run_until_complete(run())

c3() означает, что некоторые сопрограммы не удастся и должны быть повторно запущены. Проблема с демонстрацией завершена, завершена задача и имеет набор исключений, поэтому, когда я вернусь к ожидающему набору, следующий цикл выполнения немедленно выйдет из строя без повторного запуска c3() поскольку он уже выполнен.

Есть ли способ очистить задачу, чтобы она снова запускала c3()? Я знаю, что экземпляр coroutine, прикрепленный к задаче, не может быть ожидаем снова, я получаю

RuntimeError('cannot reuse already awaited coroutine',)

что означает, что мне нужно вручную управлять картой из экземпляра coroutine в task._coro который сгенерировал его, а затем извлечь неудачный экземпляр coroutine с task._coro - это правильно?

Теги:
async-await
python-asyncio
coroutine

1 ответ

1
Лучший ответ

EDIT: сама задача может быть ключом на карте, который является более чистым.

async def run():
    tasks = {asyncio.ensure_future(c()): c for c in (c1, c2, c3)}
    pending = set(tasks.keys())

    num_times_called = 0
    while pending:
        num_times_called += 1
        print("{} times called with {} pending tasks: {}".format(num_times_called, len(pending), pending))

        finished, pending = await asyncio.wait(pending, return_when=asyncio.FIRST_EXCEPTION)
        for task in finished:
            if task.exception():
                print("{} got an exception {}, retrying".format(task, task.exception()))
                coro = tasks[task]
                new_task = asyncio.ensure_future(coro())
                tasks[new_task] = coro
                pending.add(new_task)

        print("finished {}".format(finished))

    print("finished all {}".format(time.time() - t))
  • 1
    Сделать coros отображение задач сопрограммная функции: coros = {loop.create_task(c()): c for c in (c1, c2, c3)} . Затем вы можете искать сопрограмму по заданию: coro = coros[task] . Все остальное должно работать как написано, и код будет чистым и использовать только открытый API.
  • 0
    @ user4815162342 Спасибо, забыл, что asyncio.wait также может взять в Задачу!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню