Я ищу pythonic asyncio "pattern" для конструкции, которая довольно часто появляется в моих программах.
Рабочее задание выполняет некоторые операции, обычно состоящие из нескольких шагов. Детали этих операций контролируются командами, отправленными из управляющей функции в рабочую задачу. Между отдельными шагами есть сон, и рабочий может принимать новые команды только во время этих сна. Новая команда должна немедленно освободить рабочую задачу из сна.
Команды представляют желаемое целевое состояние. Я использую очередь для связи. Однако может быть только одна цель, поэтому команды не создают настоящую очередь, но последняя заменяет все предыдущие. В очереди есть не более одного элемента.
В настоящее время я использую другую асинхронную библиотеку. Я хочу перейти на стандартный asyncio
. Пример:
# warning: not asyncio code; not real code
cmd_queue = Queue()
async def worker():
cmd = 'INIT'
while cmd != 'STOP':
... do_something1 sync or async ...
newcmd = await cmd_queue.get(timeout=SLEEPTIME1, timeout_value=None)
if newcmd is not None:
cmd = newcmd
continue
... do_something2 sync or async ...
newcmd = await cmd_queue.get(timeout=SLEEPTIME2, timeout_value=None)
if newcmd is not None:
cmd = newcmd
continue
def controlloler():
...
if newcmd:
cmd_queue.clear() # replaces a waiting command
cmd_queue.put(newcmd) # put_nowait() in asyncio
...
Я мог бы переписать эту форму queue.get
на асинхронный код:
try:
cmd=wait_for(cmd_queue.get(), timeout=SLEEPTIME)
continue # or process otherwise
except asyncio.TimeoutError:
pass
но я думаю, может быть, есть более простое решение. OTOH Если у вас есть асинхронный опыт и думаю, что очередь с тайм-аутом - это путь, который мне тоже поможет.
Я попытался выполнить поиск, но не смог найти подходящие ключевые слова для моей проблемы (то же самое относится к заголовку вопроса).
Конечно, нет ничего плохого в вашей реализации тайм-аута. Методы для примитивов синхронизации asyncio намеренно не поддерживают явные аргументы тайм-аута, оставляя его вызывающему пользователю использовать отмену или wait_for
для тайм-аута, когда это необходимо.
Что касается одноэлементной очереди, я бы рассмотрел ее замену на Future
, которое предназначено не только для хранения одного значения, но также очень легкое в asyncio, учитывая, что это основная абстракция, используемая для создания почти всего остального.
Вместо wait_for(cmd_queue.get(),...)
вы должны написать wait_for(cmd_future,...)
, а вместо cmd_queue.put(value)
вы должны написать cmd_future.set_result(value)
. Единственное важное отличие состоит в том, что будущее одноразовое, поэтому после получения элемента вам нужно назначить новое будущее для cmd_future
.