跳转至

17. 异步生成器

17. Asynchronous Generators

生成器是 Python 的基本组成部分。

生成器是一种至少具有一个“yield”表达式的函数。 它们是可以暂停和恢复的函数,就像协程一样。

事实上,Python 协程是 Python 生成器的扩展。

Asyncio 允许我们开发异步生成器。

我们可以通过定义使用“yield”表达式的协程来创建异步生成器。

让我们仔细看看。

Generators are a fundamental part of Python.

A generator is a function that has at least one “yield” expression. They are functions that can be suspended and resumed, just like coroutines.

In fact, Python coroutines are an extension of Python generators.

Asyncio allows us to develop asynchronous generators.

We can create an asynchronous generator by defining a coroutine that makes use of the “yield” expression.

Let’s take a closer look.

17.1 什么是异步生成器

17.1 What Are Asynchronous Generators

异步生成器是使用yield 表达式的协程。

在我们深入了解异步生成器的细节之前,让我们首先回顾一下经典的 Python 生成器。

An asynchronous generator is a coroutine that uses the yield expression.

Before we dive into the details of asynchronous generators, let’s first review classical Python generators.

17.1.1 生成器

17.1.1 Generators

生成器是一个Python函数,它通过yield表达式返回一个值。

例如:

# 定义生成器
def generator():
    for i in range(10):
        yield i

生成器执行到yield表达式,然后返回一个值。 这会在此时暂停生成器。 下次执行生成器时,它将从恢复点恢复并运行到下一个 yield 表达式。

生成器: 返回生成器迭代器的函数。 它看起来像一个普通函数,只不过它包含用于生成一系列可在 for 循环中使用的值的yield 表达式,或者可以使用 next() 函数一次检索一个值。

PYTHON GLOSSARY

从技术上讲,生成器函数创建并返回生成器迭代器。 生成器迭代器执行生成器函数的内容,根据需要产生并恢复。

生成迭代器: 由生成器函数创建的对象。 每个yield都会暂时挂起处理,记住位置执行状态[...]当生成器迭代器恢复时,它会从上次停止的地方继续...

PYTHON GLOSSARY

可以使用 next() 内置函数逐步执行生成器。

例如:

...
# 创建生成器
gen = generator()
# 生成器的下一步
result = next(gen)

尽管如此,更常见的是迭代生成器以完成,例如使用 for 循环或列表理解。

例如:

...
# 遍历生成器并收集结果
results = [item for item in generator()]

接下来,让我们仔细看看异步生成器。

A generator is a Python function that returns a value via a yield expression.

For example:

# define a generator
def generator():
    for i in range(10):
        yield i

The generator is executed to the yield expression, after which a value is returned. This suspends the generator at that point. The next time the generator is executed it is resumed from the point it was resumed and runs until the next yield expression.

generator: A function which returns a generator iterator. It looks like a normal function except that it contains yield expressions for producing a series of values usable in a for-loop or that can be retrieved one at a time with the next() function.

PYTHON GLOSSARY

Technically, a generator function creates and returns a generator iterator. The generator iterator executes the content of the generator function, yielding and resuming as needed.

generator iterator: An object created by a generator function. Each yield temporarily suspends processing, remembering the location execution state […] When the generator iterator resumes, it picks up where it left off …

PYTHON GLOSSARY

A generator can be executed in steps by using the next() built-in function.

For example:

...
# create the generator
gen = generator()
# step the generator
result = next(gen)

Although, it is more common to iterate the generator to completion, such as using a for-loop or a list comprehension.

For example:

...
# traverse the generator and collect results
results = [item for item in generator()]

Next, let’s take a closer look at asynchronous generators.

17.1.2 异步生成器

17.1.2 Asynchronous Generators

异步生成器是使用yield 表达式的协程。

与函数生成器不同,协程可以调度和等待其他协程和任务。

异步生成器: 返回异步生成器迭代器的函数。 它看起来像一个使用 async def 定义的协程函数,只不过它包含用于生成一系列可在 async for 循环中使用的值的 yield 表达式。

PYTHON GLOSSARY

与经典生成器一样,异步生成器函数可用于创建异步生成器迭代器,该迭代器可以使用内置 anext() 函数(而不是 next() 函数)进行遍历。

基于异步生成器的迭代器:由异步生成器函数创建的对象。 这是一个异步迭代器,当使用 __anext__() 方法调用时,它会返回一个可等待对象,该对象将执行异步生成器函数的主体,直到下一个 yield 表达式。

PYTHON GLOSSARY

这意味着异步生成器迭代器实现了 __anext__() 方法,并且可以与 async for 表达式一起使用。

这意味着生成器的每次迭代都被调度并作为可等待执行。 “async for”表达式将调度并执行生成器的每次迭代,挂起调用协程并等待结果。

您可以在教程中了解有关“async for”表达式的更多信息:

An asynchronous generator is a coroutine that uses the yield expression.

Unlike a function generator, the coroutine can schedule and await other coroutines and tasks.

asynchronous generator: A function which returns an asynchronous generator iterator. It looks like a coroutine function defined with async def except that it contains yield expressions for producing a series of values usable in an async for loop.

PYTHON GLOSSARY

Like a classical generator, an asynchronous generator function can be used to create an asynchronous generator iterator that can be traversed using the built-in anext() function, instead of the next() function.

asynchronous generator iterator: An object created by a asynchronous generator function. This is an asynchronous iterator which when called using the __anext__() method returns an awaitable object which will execute the body of the asynchronous generator function until the next yield expression.

PYTHON GLOSSARY

This means that the asynchronous generator iterator implements the __anext__() method and can be used with the async for expression.

This means that each iteration of the generator is scheduled and executed as awaitable. The “async for” expression will schedule and execute each iteration of the generator, suspending the calling coroutine and awaiting the result.

You can learn more about the “async for” expression in the tutorial:

17.2 如何使用异步生成器

17.2 How to Use an Asynchronous Generator

在本节中,我们将仔细研究如何在 asyncio 程序中定义、创建、单步执行和遍历异步生成器。

让我们从如何定义异步生成器开始。

In this section, we will take a close look at how to define, create, step, and traverse an asynchronous generator in asyncio programs.

Let’s start with how to define an asynchronous generator.

17.2.1 定义异步生成器

17.2.1 Define an Asynchronous Generator

我们可以通过定义一个至少具有一个yield 表达式的协程来定义异步生成器。

这意味着该函数是使用“async def”表达式定义的。

例如:

# 定义一个异步生成器
async def async_generator():
    for i in range(10)
        yield i

因为异步生成器是一个协程,并且每个迭代器返回一个在 asyncio 事件循环中调度和执行的等待对象,所以我们可以在生成器的主体内执行和等待等待对象。

例如:

# 定义一个等待的异步生成器
async def async_generator():
    for i in range(10)
        # 暂停并睡眠一会儿
        await asyncio.sleep(1)
        # 向调用者产生一个值
        yield i

接下来,让我们看看如何使用异步生成器。

We can define an asynchronous generator by defining a coroutine that has at least one yield expression.

This means that the function is defined using the “async def” expression.

For example:

# define an asynchronous generator
async def async_generator():
    for i in range(10)
        yield i

Because the asynchronous generator is a coroutine and each iterator returns an awaitable that is scheduled and executed in the asyncio event loop, we can execute and await awaitables within the body of the generator.

For example:

# define an asynchronous generator that awaits
async def async_generator():
    for i in range(10)
        # suspend and sleep a moment
        await asyncio.sleep(1)
        # yield a value to the caller
        yield i

Next, let’s look at how we might use an asynchronous generator.

17.2.2 创建异步生成器

17.2.2 Create Asynchronous Generator

要使用异步生成器,我们必须创建生成器。

这看起来像是调用它,但实际上是创建并返回一个迭代器对象。

例如:

...
# 创建迭代器
it = async_generator()

这会返回一种称为异步生成器的可迭代的异步迭代器。

To use an asynchronous generator we must create the generator.

This looks like calling it, but instead creates and returns an iterator object.

For example:

...
# create the iterator
it = async_generator()

This returns a type of asynchronous iterator called an asynchronous generator iterator.

17.2.3 使用异步生成器

17.2.3 Step an Asynchronous Generator

可以使用 anext() 内置函数遍历生成器的一步,就像使用 next() 函数的经典生成器一样 。

结果是一个值得期待的结果。

例如:

...
# 获取生成器一步的等待值
awaitable = anext(gen)
# 执行生成器的一步并得到结果
result = await awaitable

这可以一步实现。

例如:

...
# 启动异步生成器
result = await anext(gen)

One step of the generator can be traversed using the anext() built-in function, just like a classical generator using the next() function.

The result is an awaitable that is awaited.

For example:

...
# get an awaitable for one step of the generator
awaitable = anext(gen)
# execute the one step of the generator and get the result
result = await awaitable

This can be achieved in one step.

For example:

...
# step the async generator
result = await anext(gen)

17.2.4 遍历异步生成器

17.2.4 Traverse an Asynchronous Generator

还可以使用“async for”表达式在循环中遍历异步生成器,该表达式将自动等待循环的每次迭代。

例如:

...
# 遍历异步生成器
async for result in async_generator():
    print(result)

您可以在教程中了解有关“async for”表达式的更多信息:

我们还可以使用异步列表理解和“async for”表达式来收集生成器的结果。

例如:

...
# 使用异步生成器的异步列表推导式
results = [item async for item in async_generator()]

The asynchronous generator can also be traversed in a loop using the “async for” expression that will await each iteration of the loop automatically.

For example:

...
# traverse an asynchronous generator
async for result in async_generator():
    print(result)

You can learn more about the “async for” expression in the tutorial:

We may also use an asynchronous list comprehension with the “async for” expression to collect the results of the generator.

For example:

...
# async list comprehension with async generator
results = [item async for item in async_generator()]

17.3 异步生成器示例

17.3 Example of an Asynchronous Generator

我们可以探索如何使用“async for”表达式遍历异步生成器。

在此示例中,我们将更新前面的示例,以使用“async for”循环遍历生成器直至完成。

该循环将自动等待从生成器返回的每个等待,检索生成的值,并使其在循环体内可用,以便在这种情况下可以报告它。

这可能是异步生成器最常见的使用模式。

下面列出了完整的示例。

# SuperFastPython.com
# 带有 async for 循环的异步生成器示例
import asyncio

# define an asynchronous generator
async def async_generator():
    # 正常循环
    for i in range(10):
        # 块来模拟做工作
        await asyncio.sleep(1)
        # 产生结果
        yield i

# 主协程
async def main():
    # 使用 async for 循环遍历异步生成器
    async for item in async_generator():
        print(item)

# 执行异步程序
asyncio.run(main())

运行该示例首先创建 main() 协程,并将其用作 asyncio 程序的入口点。

main() 协程运行并启动 for 循环。

创建异步生成器的实例,循环使用 anext() 函数自动步进它以返回可等待的对象。 然后,循环等待可等待对象并检索一个值,该值可供报告该值的循环体使用。

然后重复这个过程,挂起 main() 协程,执行生成器的迭代,挂起并恢复 main() 协程,直到生成器耗尽。

这突出显示了如何使用 async for 表达式遍历异步生成器。

0
1
2
3
4
5
6
7
8
9

您可以在教程中了解有关异步生成器的更多信息:

接下来,我们将探讨异步上下文管理器。

We can explore how to traverse an asynchronous generator using the “async for” expression.

In this example, we will update the previous example to traverse the generator to completion using an “async for” loop.

This loop will automatically await each awaitable returned from the generator, retrieve the yielded value, and make it available within the loop body so that in this case it can be reported.

This is perhaps the most common usage pattern for asynchronous generators.

The complete example is listed below.

# SuperFastPython.com
# example of asynchronous generator with async for loop
import asyncio

# define an asynchronous generator
async def async_generator():
    # normal loop
    for i in range(10):
        # block to simulate doing work
        await asyncio.sleep(1)
        # yield the result
        yield i

# main coroutine
async def main():
    # loop over async generator with async for loop
    async for item in async_generator():
        print(item)

# execute the asyncio program
asyncio.run(main())

Running the example first creates the main() coroutine and uses it as the entry point into the asyncio program.

The main() coroutine runs and starts the for loop.

An instance of the asynchronous generator is created and the loop automatically steps it using the anext() function to return an awaitable. The loop then awaits the awaitable and retrieves a value which is made available to the body of the loop where it is reported.

This process is then repeated, suspending the main() coroutine, executing an iteration of the generator, and suspending, and resuming the main() coroutine until the generator is exhausted.

This highlights how an asynchronous generator can be traversed using an async for expression.

0
1
2
3
4
5
6
7
8
9

You can learn more about async generators in the tutorial:

Next, we will explore asynchronous context managers.


最后更新: 2024年9月4日
创建日期: 2024年9月4日