在异步中的睡眠期间检查新的控制命令

时间:2018-08-04 14:24:53

标签: python python-asyncio

我正在寻找一种在程序中经常出现的构造的pythonic asyncio“模式”。

工作者任务执行一些通常由几个步骤组成的操作。这些操作的详细信息由从控制功能发送到工作人员任务的命令控制。在各个步骤之间存在睡眠,并且工作人员仅在这些睡眠期间才能接受新命令。一个新命令应立即将工作者任务从睡眠中唤醒。

命令表示所需的目标状态。我正在使用队列进行通信。但是,只能有一个目标,这就是为什么这些命令不建立真实队列的原因,而最后一个替换了之前的所有队列。队列中最多只有一个项目。

目前,我正在使用其他异步库。我想切换到标准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如果您有异步的经验,并且认为超时是一个可行的方法,那对我也有帮助。

我尝试搜索,但是找不到适合我的问题的关键字(问题标题也是如此)。

1 个答案:

答案 0 :(得分:1)

您的超时实现肯定没有错。异步synchronization原语上的方法有意不支持显式的超时参数,将其留给调用方使用取消或wait_for可以在需要时超时。

对于单元素队列,我会考虑用Future替换它,该队列不仅被设计为保存单个值,而且由于它是用于构建几乎所有其他内容。

您将写wait_for(cmd_queue.get(), ...)而不是wait_for(cmd_future, ...),而是写cmd_queue.put(value)而不是cmd_future.set_result(value)。唯一重要的区别是前途是一次性的,因此在获得物品后,您需要为cmd_future分配新的前途。