如何在不使用await的情况下分割一个长的协同进程?

2024-04-19 12:24:29 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个协同程序,是越来越大,我想分裂它的可读性。你知道吗

async def handle_message(self, message):
    message_type = message.get('type')

    if message_type == 'broadcast':
        ...
        for n in self._neighbors:
            await self.send_message(n, message)

    elif message_type == 'graph':
        ...

我想将处理广播消息的部分提取到一个私有方法中,如下所示:

async def handle_message(self, message):
    message_type = message.get('type')
    ...

    if message_type = 'broadcast':
        await self._handle_broadcast(message)
    elif message_type = 'graph':
        ...

问题是,这会改变代码的行为,因为_handle_broadcast部分是一个协程,而且它的执行可能会延迟,因为我用await调用它。你知道吗

如何确保协同程序立即运行并且不被延迟?你知道吗


Tags: selfmessageforgetasyncifdeftype
1条回答
网友
1楼 · 发布于 2024-04-19 12:24:29

简而言之:使用await,完全按照开始的方式拆分协同程序。你知道吗

The problem is that this changes the behavior of the code, since the _handle_broadcast part is a coroutine and its execution might be delayed since I call it with await.

不管是好是坏,这个前提是错误的。当给定一个协程时,await立即开始执行它,没有中间延迟。只有如果协同程序调用某个导致它挂起的东西(例如asyncio.sleep或一个还没有数据的网络读取),您的协同程序才会随之挂起—这正是代码保持内联时您将得到的结果。你知道吗

从这个意义上说,await <some coroutine>的工作方式类似于常规函数调用的协同程序,它允许您所需要的那种不改变语义的重构。这可以用一个例子来说明:

import asyncio

async def heartbeat():
    while True:
        print('tick')
        await asyncio.sleep(1)

async def noop():
    pass

async def coro():
    # despite "await", this blocks the event loop!
    while True:
        await noop()

loop = asyncio.get_event_loop()
loop.create_task(heartbeat())
loop.create_task(coro())
loop.run_forever()

上面的代码阻塞了事件循环—即使coro除了循环中的await之外什么都不做。因此await并不能保证屈服于事件循环,协同程序必须用其他方法来完成。(此行为也可能是bugs的来源。)

在上面的例子中,可以通过插入一个await asyncio.sleep(0)来“解除”事件循环。但是在生产异步代码中不应该需要这种东西,在这种代码中,程序的结构应该使每个协同程序所做的工作相对较少,然后使用await来获取更多的数据。你知道吗

相关问题 更多 >