相关疑难解决方法(0)

asyncio实际上如何工作?

这个问题是由我的另一个问题推动的:如何在cdef中等待?

网上有大量的文章和博客文章asyncio,但它们都非常肤浅.我找不到任何有关如何asyncio实际实现的信息,以及I/O异步的原因.我试图阅读源代码,但它是成千上万行不是最高级别的C代码,其中很多处理辅助对象,但最重要的是,很难在Python语法和它将翻译的C代码之间建立连接成.

Asycnio自己的文档甚至没那么有用.没有关于它是如何工作的信息,只有关于如何使用它的一些指导,这些指导有时也会误导/写得很差.

我熟悉Go的coroutines实现,并且希望Python做同样的事情.如果是这种情况,我在上面链接的帖子中出现的代码就可以了.既然没有,我现在正试图找出原因.到目前为止我最好的猜测如下,请纠正我错在哪里:

  1. 表单的过程定义async def foo(): ...实际上被解释为类继承的方法coroutine.
  2. 也许,async def实际上是通过await语句拆分成多个方法,其中调用这些方法的对象能够跟踪到目前为止通过执行所做的进度.
  3. 如果上述情况属实,那么,从本质上讲,协程的执行归结为一些全局管理器调用协程对象的方法(循环?).
  4. 全局管理器以某种方式(如何?)了解I/O操作何时由Python(仅?)代码执行,并且能够在当前执行方法放弃控制之后选择一个待执行的协程方法执行(命中await语句) ).

换句话说,这是我尝试将某些asyncio语法"贬低"为更容易理解的东西:

async def coro(name):
    print('before', name)
    await asyncio.sleep()
    print('after', name)

asyncio.gather(coro('first'), coro('second'))

# translated from async def coro(name)
class Coro(coroutine):
    def before(self, name):
        print('before', name)

    def after(self, name):
        print('after', name)

    def __init__(self, name):
        self.name = name
        self.parts = self.before, self.after
        self.pos = 0

    def __call__():
        self.parts[self.pos](self.name)
        self.pos += 1

    def …
Run Code Online (Sandbox Code Playgroud)

python python-3.x python-asyncio

64
推荐指数
5
解决办法
1万
查看次数

我怎样才能在未来的对象__await__中等待?

PEP 0492增加了新的__await__魔法.实现此方法的对象变为类似未来的对象,可以等待使用await.很明显:

import asyncio


class Waiting:
    def __await__(self):
        yield from asyncio.sleep(2)
        print('ok')

async def main():
    await Waiting()

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
Run Code Online (Sandbox Code Playgroud)

好的,但如果我想调用一些已async def定义的函数而不是asyncio.sleep?我不能使用await因为__await__不是async函数,我无法使用yield from因为本机协同程序需要await表达式:

async def new_sleep():
    await asyncio.sleep(2)

class Waiting:
    def __await__(self):
        yield from new_sleep()  # this is TypeError
        await new_sleep()  # this is SyntaxError
        print('ok')
Run Code Online (Sandbox Code Playgroud)

我该如何解决?

python python-3.x async-await python-asyncio

28
推荐指数
5
解决办法
6410
查看次数

Python原生协同程序和send()

基于生成器的协同程序具有send()允许调用者和被调用者之间的双向通信并且从调用者恢复生成的生成器协同程序的方法.这是将生成器转换为协同程序的功能.

虽然新的本机async/await协同程序为异步I/O提供了出色的支持,但我看不出如何send()使用它们.明确禁止使用yieldin async函数,因此本机协同程序只能使用return语句返回一次.虽然await表达式为协程带来了新的值,但这些值来自被叫者,而不是来电者,等待的呼叫每次都从头开始评估,而不是从它停止的地方开始.

有没有办法从它停止的地方恢复返回的协同程序,并可能发送一个新值?如何使用本机协同程序模拟David Beazley 关于协同程序和并发好奇课程中的技巧

我想到的一般代码模式就像

def myCoroutine():
  ...
  while True:
    ...
    ping = yield(pong)
    ...
Run Code Online (Sandbox Code Playgroud)

并在呼叫者

while True:
  ...
  buzz = myCoroutineGen.send(bizz)
  ...
Run Code Online (Sandbox Code Playgroud)

编辑

我接受了Kevin的回答,但我注意到PEP

协同程序在内部基于生成器,因此它们共享实现.与生成器对象类似,协同程序具有throw(),send()和close()方法.

...

用于协同程序的throw(),send()方法用于推送值并将错误引发到类似Future的对象中.

显然,原生协同程序确实有一个send()?如果没有yield表达式来接收协程内的值,它如何工作?

python coroutine async-await

15
推荐指数
3
解决办法
3430
查看次数

Python 中的`await` 是否屈服于事件循环?

我想知道当我们await在异步 Python 代码中使用协程时究竟会发生什么,例如:

await send_message(string)
Run Code Online (Sandbox Code Playgroud)

(1)send_message加入事件循环,调用协程放弃对事件循环的控制,或

(2) 我们直接跳进去 send_message

我读到的大多数解释都指向 (1),因为它们将调用协程描述为exiting。但我自己的实验表明(2)是这种情况:我试图在调用者之后但在被调用者之前运行一个协程,但无法实现这一点。

python asynchronous python-3.x async-await python-asyncio

8
推荐指数
1
解决办法
3195
查看次数