Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/298.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python async和await关键字究竟是如何工作的?什么';在等待链的末端是什么?_Python_Python 3.x_Async Await_Python Asyncio - Fatal编程技术网

Python async和await关键字究竟是如何工作的?什么';在等待链的末端是什么?

Python async和await关键字究竟是如何工作的?什么';在等待链的末端是什么?,python,python-3.x,async-await,python-asyncio,Python,Python 3.x,Async Await,Python Asyncio,我有以下代码: async def foo(x): yield x yield x + 1 async def intermediary(y): await foo(y) def bar(): c = intermediary(5) 要从c中得到5和6,我应该在条中输入什么 我这样问是因为asyncio库看起来很神奇。我想知道魔法到底是怎么起作用的 也许我想编写自己的函数,调用read或write,然后通知我编写的某个顶级循环,它们正在等待文件描述符变得可读

我有以下代码:

async def foo(x):
    yield x
    yield x + 1

async def intermediary(y):
    await foo(y)

def bar():
    c = intermediary(5)
要从
c
中得到5和6,我应该在条中输入什么

我这样问是因为
asyncio
库看起来很神奇。我想知道魔法到底是怎么起作用的

也许我想编写自己的函数,调用
read
write
,然后通知我编写的某个顶级循环,它们正在等待文件描述符变得可读或可写

然后,也许我希望,一旦这些条件变为现实,顶层循环能够恢复我的读写函数(以及顶层循环和它们之间的整个中间链)

我已经或多或少知道如何使用
asyncio
。我写这篇文章是为了在延迟后计算平方,但在一个随机间隔后启动许多任务,每个任务都附加到一个列表中。它写得有点笨拙,但它很管用

我想知道这个项目到底在做什么。为了做到这一点,我必须知道wait on the sleep是如何通知顶级事件循环它想休眠(并再次被调用)一段时间的,以及调用sleep和顶级事件循环之间的所有中间堆栈帧的状态是如何被冻结的,然后在延迟结束时重新激活的,看起来和你想做的差不多。它包含一个睡眠调用(用来代替IO),因此asyncio特性是有意义的

import asyncio

async def compute(x, y):
    print("Compute %s + %s ..." % (x, y))
    await asyncio.sleep(1.0)
    return x + y

async def print_sum(x, y):
    result = await compute(x, y)
    print("%s + %s = %s" % (x, y, result))

loop = asyncio.get_event_loop()
loop.run_until_complete(print_sum(1, 2))
loop.close()
有一个,看起来几乎和你想做的完全一样。它包含一个睡眠调用(用来代替IO),因此asyncio特性是有意义的

import asyncio

async def compute(x, y):
    print("Compute %s + %s ..." % (x, y))
    await asyncio.sleep(1.0)
    return x + y

async def print_sum(x, y):
    result = await compute(x, y)
    print("%s + %s = %s" % (x, y, result))

loop = asyncio.get_event_loop()
loop.run_until_complete(print_sum(1, 2))
loop.close()

您是否尝试过查看asyncio.sleep的源代码

@coroutine                                                                       
def sleep(delay, result=None, *, loop=None):                                     
    """Coroutine that completes after a given time (in seconds)."""              
    if delay == 0:                                                               
        yield                                                                    
        return result                                                            

    if loop is None:                                                             
        loop = events.get_event_loop()                                           
    future = loop.create_future()                                                
    h = future._loop.call_later(delay,                                           
                                futures._set_result_unless_cancelled,            
                                future, result)                                  
    try:                                                                         
        return (yield from future)                                               
    finally:                                                                     
        h.cancel()

基本上,它使用loop.call\u later设置未来,然后等待未来。不确定这是否完全回答了您的问题,但它可能会有所帮助。

您是否尝试查看asyncio.sleep的源代码

@coroutine                                                                       
def sleep(delay, result=None, *, loop=None):                                     
    """Coroutine that completes after a given time (in seconds)."""              
    if delay == 0:                                                               
        yield                                                                    
        return result                                                            

    if loop is None:                                                             
        loop = events.get_event_loop()                                           
    future = loop.create_future()                                                
    h = future._loop.call_later(delay,                                           
                                futures._set_result_unless_cancelled,            
                                future, result)                                  
    try:                                                                         
        return (yield from future)                                               
    finally:                                                                     
        h.cancel()

基本上,它使用loop.call\u later设置未来,然后等待未来。不确定这是否完全回答了您的问题,但它可能会有所帮助。

仔细阅读您上面提供的代码,包含
收益率的
异步def
会创建:

要使用其中的数据,请使用
async for

async def intermediary(y):
    results = []
    async for x in foo(y):
        results.append(x)
    return results
要从一个普通函数中使用一个简单的协同程序(如
中介
)的结果,您需要创建一个事件循环,并使用
运行直到\u完成()


仔细阅读上面提供的代码,包含
产量的
异步def
会创建:

要使用其中的数据,请使用
async for

async def intermediary(y):
    results = []
    async for x in foo(y):
        results.append(x)
    return results
要从一个普通函数中使用一个简单的协同程序(如
中介
)的结果,您需要创建一个事件循环,并使用
运行直到\u完成()


所以,我更了解如何让我想做的事情发挥作用。我的代码应该是这样读的:

import types

@types.coroutine
def foo(x):
    yield x
    yield x + 1

async def intermediary(y):
    await foo(y)

def bar():
    c = intermediary(5)
    try:
        while True:
            result = c.send(None)
            print(f"Got {result} from the coroutine.")
    except StopIteration as e:
        print(f"StopIteration exception: {e!r}")
基本的答案是,它的端点可以是一个用
类型修饰的普通生成器。coroutine
。有更多的方法可以实现这一点,对我的代码的进一步修改说明了这一点:

import types
from collections.abc import Awaitable

@types.coroutine
def foo(x):
    sent = yield x
    print(f"foo was sent {sent!r}.")
    sent = yield x + 1
    print(f"foo was sent {sent!r}.")
    return 'generator'

class MyAwaitable(Awaitable):
    def __init__(self, x):
        super().__init__()
        self.x_ = x
    def __await__(self):
        def gen(x):
            for i in range(x-1, x+2):
                sent = yield i
                print(f"MyAwaitable was sent {sent!r}.")
            return 'class'
        return iter(gen(self.x_))

async def intermediary(t, y):
    awaited = await t(y)
    print(f"Got {awaited!r} as value from await.")

def runco(chain_end):
    c = intermediary(chain_end, 5)
    try:
        sendval = None
        while True:
            result = c.send(sendval)
            print(f"Got {result} from the coroutine.")
            sendval = sendval + 1 if sendval is not None else 0
    except StopIteration as e:
        print(f"StopIteration exception: {e!r}")
正如您所看到的,任何定义返回迭代器的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuu
方法的东西都可以被
等待。真正发生的情况是,正在等待的对象被迭代,直到停止,然后等待返回。这样做的原因是,链末端的最后一件事可能会遇到某种阻塞条件。然后,它可以通过
yield
ing或从迭代器返回值(基本上与
yield
ing相同)报告该条件(或请求设置回调或其他内容)。然后顶层循环可以继续运行到任何其他可以运行的东西

整个
wait
调用链的本质是,当您返回并从迭代器中请求下一个值时(回调被阻止的函数,告诉它现在可能没有被阻止),整个调用堆栈被重新激活。整个链的存在是为了在调用被阻止时保持调用堆栈的状态。基本上是一个主动放弃控制而不是让调度程序从中夺取控制的线程

当我问这个问题时,我脑海中关于
asyncio
如何在内部工作的愿景显然是调用的东西是如何工作的,并且基于端点例程
yield
ing某种指示器,指示它们被什么阻止,以及运行它的顶级循环(在我的示例中是
runco
)然后把它放在某种通用的条件池中去寻找,这样一旦条件被改变阻塞,它就可以恢复例程。在
asyncio
中,发生了更复杂的事情,它使用带有
\uuuuuwait\uuuuuuu
方法的对象(如我的示例中的
mywaitable
)和某种回调机制来实现这一切

Brett Cannon写了一篇非常好的文章,谈到了。这将比我在回答中所能说的要详细得多

我发现了一个有趣的小道消息,当你这么做的时候:

def foo(x):
    yield 11

bar = types.coroutine(foo)

foo
bar
都成为“协同程序”,可以
wait
打开。decorator所做的只是在
foo.\uuuu code\uuuu.co\u标志中翻转一点
。当然,这是一个实现细节,不应依赖。我认为这实际上是一个bug,我可能会这样报告。

因此,我更了解如何使我试图做的工作起作用。我的代码应该是这样读的:

import types

@types.coroutine
def foo(x):
    yield x
    yield x + 1

async def intermediary(y):
    await foo(y)

def bar():
    c = intermediary(5)
    try:
        while True:
            result = c.send(None)
            print(f"Got {result} from the coroutine.")
    except StopIteration as e:
        print(f"StopIteration exception: {e!r}")
基本的答案是,它的端点可以是一个用
类型修饰的普通生成器。coroutine
。有更多的方法来实现这一点,还有对我的代码的进一步修改