В asyncio вы можете разделить службу на три отдельные задачи, каждая со своим собственным циклом и временем - вы можете думать о них как о трех потоках, за исключением того, что они все запланированы в одном потоке, и многозадачность совместно выполняется путем приостановки наawait
.
Для этого давайте начнем с служебной функции, которая вызывает функцию и проверяет ее результат через регулярный интервал:
async def at_interval(f, check, seconds):
while True:
feedback = f()
if check(feedback):
return feedback
await asyncio.sleep(seconds)
return
является эквивалентомbreak
в исходном коде.
С этим на месте служба порождает три таких цикла и ждет завершения любого из них.То, что завершится первым, несет ожидаемую «обратную связь», и мы можем распоряжаться остальными.
async def service():
loop = asyncio.get_event_loop()
t1 = loop.create_task(at_interval(f1, check1, 3))
t2 = loop.create_task(at_interval(f2, check2, 5))
t3 = loop.create_task(at_interval(f3, check3, 7))
done, pending = await asyncio.wait(
[t1, t2, t3], return_when=asyncio.FIRST_COMPLETED)
for t in pending:
t.cancel()
feedback = await list(done)[0]
do_cleanup(feedback)
asyncio.get_event_loop().run_until_complete(service())
Небольшая разница между этим и вашим кодом заключается в том, что здесь это возможно (хотя и маловероятно)более чем одна проверка не пройдена до того, как service
обнаружит ее.Например, если из-за неудачи две из вышеперечисленных задач в итоге разделят абсолютное время пробуждения с микросекундой, они будут запланированы в одной и той же итерации цикла событий.Оба вернутся из своих сопрограмм at_interval
, а done
будет содержать более одного отзыва.Код обрабатывает его, выбирая обратную связь и вызывая do_cleanup
для этого, но он также может зацикливаться на всех.
Если это не приемлемо, вы можете легко передать каждому at_interval
вызываемый элемент, который отменяет всезадачи кроме себя.В настоящее время это делается для краткости в service
, но может быть сделано и в at_interval
.Одна задача отмены других будет гарантировать, что может существовать только одна обратная связь.