Я попытался создать метод, похожий на asyncio.gather, но который будет выполнять список задач последовательно, а не асинхронно:
async def in_sequence(*tasks):
"""Executes tasks in sequence"""
for task in tasks:
await task
Далее этот метод должен был использоваться следующим образом:
async def some_work(work_name):
"""Do some work"""
print(f"Start {work_name}")
await asyncio.sleep(1)
if raise_exception:
raise RuntimeError(f"{work_name} raise an exception")
print(f"Finish {work_name}")
async def main():
try:
await asyncio.gather(
some_work("work1"), # work1, work2, in_sequence and work5 executed in concurrently
some_work("work2"),
in_sequence(
some_work("work3"), # work3 and work4 executed in sequence
some_work("work4")
),
some_work("work5"),
except RuntimeError as error:
print(error) # raise an exception at any point to terminate
И все работало нормально, пока я не попытался вызвать исключение в some_work:
async def main():
try:
await asyncio.gather(
some_work("work1"),
some_work("work2"),
in_sequence(
some_work("work3", raise_exception=True), # raise an exception here
some_work("work4")
),
some_work("work5"),
except RuntimeError as error:
print(error)
Сразу после этого я получил следующее сообщение об ошибке:
RuntimeWarning: coroutine 'some_work' was never awaited
Я прочитал документацию и продолжил экспериментировать:
async def in_sequence(*tasks):
"""Executes tasks in sequence"""
_tasks = []
for task in tasks:
_tasks.append(asyncio.create_task(task))
for _task in _tasks:
await _task
И эта версия сработала как положено!
В связи с этим у меня возникли следующие вопросы:
- Почему работает ли вторая версия, а первая нет?
- Есть ли в Asyncio инструменты для последовательного выполнения списка задач?
- Я выбрал правильный метод реализации или есть лучшие варианты?