如何实现wait_for逻辑,以使其不会阻塞事件循环

时间:2019-05-27 11:05:18

标签: python-asyncio python-3.7 event-loop

目前我正在编写一段代码,大量使用python 3.7的asyncio功能。该代码非常复杂,因此希望我能够正确描述我所面临的问题及其触发的问题。

程序的主入口使用process_*()调用各种gather待命对象

await asyncio.gather(self.process_api_events(),...)

基本上所有排队工作的人都在做

async def process_api_events(self):
    while True:
        api_event = await self.api_events_queue.get(),...)
        ...
        await self.starting(sim_uid)

process_api_events()发出一个starting请求,该请求本身是可以等待的。它尝试启动docker容器并等待来自容器的通知。通知的逻辑发生在其他地方(为了简单起见,我将其省略)。 但是,将创建一个Future,该future应该在容器出现后等待来自容器的通知。未来等待300秒。当收到来自容器的通知时,将来的结果将像future.set_result(state.value)那样设置。

state = await asyncio.wait_for(
    future, timeout=CONTAINER_UP_TIMEOUT)  # [300 secs]

当然,提起容器可能会失败。没有通知将被发送。因此,整个事件循环挂起。我喜欢使用将来检查容器状态的想法。我有什么选择可以无阻地检查我的未来状态?一个新的事件循环?完全不同的线程?

出于完整性考虑,我还发布了整个starting()方法

async def starting(self, sim_uid: str):

    # start the container
    await self.container_crane_heave(sim_uid)

    # Create future to wait for container to come up
    future = asyncio.get_event_loop().create_future()

    async def process_state(state: CoreSimulationState):
        logger.warning('calccore_state %s ', state)
        if state.in_start_up_set:
            if not future.done():
                future.set_result(state.value)

    if sim_uid not in self.state_processors:
        self.state_processors[sim_uid] = []

    # once the notification from the container comes in, 
    # the process_state() will be called  
    self.state_processors[sim_uid].append(process_state)

    state = await asyncio.wait_for(
        future, timeout=CONTAINER_UP_TIMEOUT)

    if CoreSimulationState(state) == CoreSimulationState.CRASHED:
        print('CRASHED!!', state)
        return

    logger.warning('calccore_state %s ', state)

0 个答案:

没有答案