【问题标题】:Suspend coroutine and return to caller挂起协程并返回给调用者
【发布时间】:2017-06-11 18:45:42
【问题描述】:

短篇小说:

yield 不能在async def 函数中用于暂停执行并返回给调用者。在 Python 3.5 中是否有其他方法可以做到这一点?

编辑: a very similar question 的答案建议使用 Python 3.6 或将异步生成器定义为一个类。不幸的是,前者目前不是一个选择。生成器可以工作,但为此目的定义一个类似乎比我自己的尝试更笨重。

大概没有干净简单的解决方案吧?

长篇大论:

我需要编写函数来暂停它们的操作,返回到调用者,然后在它们停止的地方继续。这些可以实现为状态机,可能使用类,这会撕裂相关代码并且通常相当不可读。借助生成器,Python 提供了一种或多或少优雅的方式来编写此类函数:

def a():
    print('A Part 1')
    yield  # suspend execution to caller
    print('A Part 2')

def run(func):
    o = func()
    try:
        while True:
            print('running...')
            o.send(None)
    except StopIteration:
        pass    

run(a)
# running...
# A Part 1
# running...
# A Part 2

Python 3.3 添加了yield from 语法,它可以很好地嵌套这些函数。 yield from 不是将执行返回给调用者,而是将执行转移到另一个函数:

def b():
    print('B Part 1')
    yield from a()
    print('B Part 2')

run(b)
# running...
# B Part 1
# A Part 1
# running...
# A Part 2
# B Part 2

Python 3.5 引入了async defawait 来区分协程和生成器。当然我宁愿使用这些原生协程。重写b 很容易,只需将def 替换为async def 并将yield from 替换为await。但是,我没有找到一种规范的方式来暂停协程并返回给调用者。 yield 在异步函数中是不允许的,await 只需要另一个函数来运行。我想出了这个尴尬的解决方案:

import asyncio

@asyncio.coroutine
def awkward_suspend():
    yield

async def c():
    print('C Part 1')
    #yield  # SyntaxError: 'yield' inside async function 
    #await  # Syntax Error: invalid syntax
    await awkward_suspend()
    print('C Part 2')    

run(c)
# running...
# C Part 1
# running...
# C Part 2

这种方法将yield 包装在一个普通函数中,从而创建一个生成器,并将生成器标记为协程,以便它可以被awaited。 这感觉就像是对语言的滥用。没有asyncio 和笨拙的挂起功能,有没有办法达到同样的效果?

【问题讨论】:

  • 谢谢@JoshLee,我想知道我是如何在搜索中错过了这个问题的。尽管它似乎与我的问题有一些共同点,但我相信它们是相当不同的。该问题的 OP 正在寻找一种从异步函数中产生(返回)值的方法。相比之下,我需要暂停一个异步函数。

标签: python python-3.5


【解决方案1】:

您可以简单地使用 sleep(0):

async def c():
    print('C Part 1')
    await asyncio.sleep(0)
    print('C Part 2')

sleep(0) 完全是笨拙的_suspend - 一个简单的收益 事实上,他们有一个私有的 __sleep0() 函数和那个 yield 语句。

【讨论】:

    猜你喜欢
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 2019-10-10
    • 2020-06-27
    • 2010-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多