16. 异步迭代器¶
16. Asynchronous Iterators
迭代是Python中的基本操作。
我们可以迭代列表、字符串和各种其他结构。
Asyncio 允许我们开发异步迭代器。
我们可以通过定义一个实现 __aiter__() 和 __anext__() 方法的对象来在 asyncio 程序中创建和使用异步迭代器。
让我们仔细看看。
Iteration is a basic operation in Python.
We can iterate lists, strings, and all manner of other structures.
Asyncio allows us to develop asynchronous iterators.
We can create and use asynchronous iterators in asyncio programs by defining an object that implements the __aiter__() and __anext__() methods.
Let’s take a closer look.
16.1 什么是异步迭代器¶
16.1 What Are Asynchronous Iterators
异步迭代器是一个实现 __aiter__() 和 __anext__() 方法的对象。
在我们仔细研究异步迭代器之前,让我们回顾一下经典迭代器。
An asynchronous iterator is an object that implements the __aiter__() and __anext__() methods.
Before we take a close look at asynchronous iterators, let’s review classical iterators.
16.1.1 迭代器¶
16.1.1 Iterators
迭代器是一个实现特定接口的 Python 对象。
具体来说, __iter__() 方法返回迭代器的实例,而 __next__() 方法步进迭代器一个周期并返回 一个值。
迭代器:表示数据流的对象。 重复调用迭代器的 __next__() 方法(或将其传递给内置函数 next())会返回流中的连续项。 当没有更多数据可用时,会引发 StopIteration 异常。
可以使用 next() 内置函数步进迭代器或使用 for 循环遍历迭代器。
许多 Python 对象都是可迭代的,最值得注意的是列表等容器。
An iterator is a Python object that implements a specific interface.
Specifically, the __iter__() method that returns an instance of the iterator and the __next__() method that steps the iterator one cycle and returns a value.
iterator: An object representing a stream of data. Repeated calls to the iterator’s __next__() method (or passing it to the built-in function next()) return successive items in the stream. When no more data are available a StopIteration exception is raised instead.
An iterator can be stepped using the next() built-in function or traversed using a for loop.
Many Python objects are iterable, most notable are containers such as lists.
16.1.2 异步迭代器¶
16.1.2 Asynchronous Iterators
异步迭代器是实现特定接口的 Python 对象。
异步迭代器:实现 __aiter__() 和 __anext__() 方法的对象。
异步迭代器必须实现 __aiter__() 和 __anext__() 方法。
- __aiter__() 方法必须返回迭代器的实例。
- __anext__() 方法必须返回一个步进迭代器的等待对象。
异步迭代器只能在异步程序中步进或遍历,例如在协程中。
异步迭代器在 PEP 492 – 具有异步和等待语法的协程 中引入。
异步迭代器可以使用 anext() 内置函数进行单步执行,该函数返回一个执行迭代器一步的等待对象, 例如 对 __anext__() 方法的一次调用。
可以使用“async for”表达式遍历异步迭代器,该表达式将在每次迭代时自动调用 anext() 并等待返回的可等待项以检索返回值。
异步迭代器可以在其 iter 实现中调用异步代码,异步迭代器可以在其 anext 方法中调用异步代码。
An asynchronous iterator is a Python object that implements a specific interface.
asynchronous iterator: An object that implements the __aiter__() and __anext__() methods.
An asynchronous iterator must implement the __aiter__() and __anext__() methods.
- The __aiter__() method must return an instance of the iterator.
- The __anext__() method must return an awaitable that steps the iterator.
An asynchronous iterator may only be stepped or traversed in an asyncio program, such as within a coroutine.
Asynchronous iterators were introduced in PEP 492 – Coroutines with async and await syntax.
An asynchronous iterator can be stepped using the anext() built-in function that returns an awaitable that executes one step of the iterator, e.g. one call to the __anext__() method.
An asynchronous iterator can be traversed using the “async for” expression that will automatically call anext() each iteration and await the returned awaitable in order to retrieve the return value.
An asynchronous iterable is able to call asynchronous code in its iter implementation, and asynchronous iterator can call asynchronous code in its next method.
16.2 什么是“async for”循环?¶
16.2 What is the “async for” loop?
async for 表达式用于遍历异步迭代器。
它是一个异步for循环语句。
异步迭代器是产生可等待对象的迭代器。
您可能还记得,awaitable 是一个可以等待的对象,例如协程或任务。
awaitable: 可在await 表达式中使用的对象。
异步生成器将自动实现异步迭代器方法,允许它像异步迭代器一样进行迭代。
wait for 表达式允许调用者遍历可等待项的异步迭代器并从每个迭代器中检索结果。
这与遍历可等待对象的集合或列表(例如协程对象)不同,相反,必须使用预期的异步迭代器方法提供返回的可等待对象。
在内部,async for 循环将自动解析或等待每个可等待的、根据需要调度协程。
因为它是一个 for 循环,所以它假设(尽管不要求)每个被遍历的可等待对象都会产生一个返回值。
async for 循环必须在协程内使用,因为它在内部将使用只能在协程内使用的await 表达式。
async for 表达式可用于遍历协程内的异步迭代器。
例如:
...
# 遍历异步迭代器
async for item in async_iterator:
print(item)
这不会并行执行 for 循环。 asyncio 无法在 Python 线程中同时执行多个协程。
相反,这是一个异步 for 循环。
不同之处在于,执行 for 循环的协程将挂起并在内部等待每个可等待项。
在幕后,这可能需要安排和等待协程,或者等待任务。
我们还可以在列表理解中使用 async for 表达式。
例如:
...
# 建立结果列表
results = [item async for item async_iterator]
这将从异步迭代器构造返回值列表。
接下来,我们看看如何定义、创建和使用异步迭代器。
The async for expression is used to traverse an asynchronous iterator.
It is an asynchronous for-loop statement.
An asynchronous iterator is an iterator that yields awaitables.
You may recall that an awaitable is an object that can be waited for, such as a coroutine or a task.
awaitable: An object that can be used in an await expression.
An asynchronous generator will automatically implement the asynchronous iterator methods, allowing it to be iterated like an asynchronous iterator.
The await for expression allows the caller to traverse an asynchronous iterator of awaitables and retrieve the result from each.
This is not the same as traversing a collection or list of awaitables (e.g. coroutine objects), instead, the awaitables returned must be provided using the expected asynchronous iterator methods.
Internally, the async for loop will automatically resolve or await each awaitable, scheduling coroutines as needed.
Because it is a for-loop, it assumes, although does not require, that each awaitable being traversed yields a return value.
The async for loop must be used within a coroutine because internally it will use the await expression, which can only be used within coroutines.
The async for expression can be used to traverse an asynchronous iterator within a coroutine.
For example:
...
# traverse an asynchronous iterator
async for item in async_iterator:
print(item)
This does not execute the for-loop in parallel. The asyncio is unable to execute more than one coroutine at a time within a Python thread.
Instead, this is an asynchronous for-loop.
The difference is that the coroutine that executes the for loop will suspend and internally await for each awaitable.
Behind the scenes, this may require coroutines to be scheduled and awaited, or tasks to be awaited.
We may also use the async for expression in a list comprehension.
For example:
...
# build a list of results
results = [item async for item async_iterator]
This would construct a list of return values from the asynchronous iterator.
Next, let’s look at how to define, create and use asynchronous iterators.
16.3 如何使用异步迭代器¶
16.3 How to Use Asynchronous Iterators
在本节中,我们将仔细研究如何在 asyncio 程序中定义、创建、单步执行和遍历异步迭代器。
让我们从如何定义异步迭代器开始。
In this section, we will take a close look at how to define, create, step, and traverse an asynchronous iterator in asyncio programs.
Let’s start with how to define an asynchronous iterator.
16.3.1 定义异步迭代器¶
16.3.1 Define an Asynchronous Iterator
我们可以通过定义一个实现 __aiter__() 和 __anext__() 方法的类来定义异步迭代器。
这些方法按照正常方式在 Python 对象上定义。
重要的是,由于 __anext__() 函数必须返回一个等待对象,因此必须使用 “async def” 表达式来定义它。
object.__anext__(self):必须返回一个可等待的结果,从而产生迭代器的下一个值。 迭代结束时应引发 StopAsyncIteration 错误。
迭代完成后, __anext__() 方法必须引发 StopAsyncIteration 异常。
例如:
# 定义一个异步迭代器
class AsyncIterator():
# 构造函数,定义一些状态
def __init__(self):
self.counter = 0
# 创建迭代器的实例
def __aiter__(self):
return self
# 返回下一个等待的
async def __anext__(self):
# 检查没有其他项目
if self.counter >= 10:
raise StopAsyncIteration
# 增加计数器
self.counter += 1
# 返回计数器值
return self.counter
因为异步迭代器是一个协程,并且每个迭代器都返回一个在 asyncio 事件循环中调度和执行的等待对象,所以我们可以在迭代器体内执行和等待等待对象。
例如:
...
# 返回下一个等待的
async def __anext__(self):
# 检查没有其他项目
if self.counter >= 10:
raise StopAsyncIteration
# 增加计数器
self.counter += 1
# 模拟工作
await asyncio.sleep(1)
# 返回计数器值
return self.counter
接下来,让我们看看如何使用异步迭代器。
We can define an asynchronous iterator by defining a class that implements the __aiter__() and __anext__() methods.
These methods are defined on a Python object as per normal.
Importantly, because the __anext__() function must return an awaitable, it must be defined using the “async def” expression.
object.__anext__(self): Must return an awaitable resulting in a next value of the iterator. Should raise a StopAsyncIteration error when the iteration is over.
When the iteration is complete, the __anext__() method must raise a StopAsyncIteration exception.
For example:
# define an asynchronous iterator
class AsyncIterator():
# constructor, define some state
def __init__(self):
self.counter = 0
# create an instance of the iterator
def __aiter__(self):
return self
# return the next awaitable
async def __anext__(self):
# check for no further items
if self.counter >= 10:
raise StopAsyncIteration
# increment the counter
self.counter += 1
# return the counter value
return self.counter
Because the asynchronous iterator 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 iterator.
For example:
...
# return the next awaitable
async def __anext__(self):
# check for no further items
if self.counter >= 10:
raise StopAsyncIteration
# increment the counter
self.counter += 1
# simulate work
await asyncio.sleep(1)
# return the counter value
return self.counter
Next, let’s look at how we might use an asynchronous iterator.
16.3.2 创建异步迭代器¶
16.3.2 Create Asynchronous Iterator
要使用异步迭代器,我们必须创建迭代器。
这涉及到按照正常方式创建 Python 对象。
例如:
...
# 创建迭代器
it = AsyncIterator()
这将返回一个“异步迭代器”,它是“异步迭代器”的实例。
To use an asynchronous iterator we must create the iterator.
This involves creating the Python object as per normal.
For example:
...
# create the iterator
it = AsyncIterator()
This returns an “asynchronous iterable“, which is an instance of an “asynchronous iterator“.
16.3.3 单步执行异步迭代器¶
Step an Asynchronous Iterator
可以使用 anext() 内置函数遍历迭代器的一步,就像使用 next() 函数的经典迭代器一样。
结果是一个可等待对象的结果。
例如:
...
# 获取迭代器一步的等待
awaitable = anext(it)
# 执行迭代器的一步并得到结果
result = await awaitable
这可以一步实现。
例如:
...
# 单步执行异步迭代器
result = await anext(it)
One step of the iterator can be traversed using the anext() built-in function, just like a classical iterator using the next() function.
The result is an awaitable that is awaited.
For example:
...
# get an awaitable for one step of the iterator
awaitable = anext(it)
# execute the one step of the iterator and get the result
result = await awaitable
This can be achieved in one step.
For example:
...
# step the async iterator
result = await anext(it)
16.3.4 遍历异步迭代器¶
Traverse an Asynchronous Iterator
还可以使用“async for”表达式在循环中遍历异步迭代器,该表达式将自动等待循环的每次迭代。
例如:
...
# 遍历异步迭代器
async for result in AsyncIterator():
print(result)
您可以在教程中了解有关“async for”表达式的更多信息:
我们还可以使用异步列表理解和“async for”表达式来收集迭代器的结果。
例如:
...
# 使用异步迭代器的异步列表推导式
results = [item async for item in AsyncIterator()]
The asynchronous iterator 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 iterator
async for result in AsyncIterator():
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 iterator.
For example:
...
# async list comprehension with async iterator
results = [item async for item in AsyncIterator()]
16.4 异步迭代器的示例¶
16.4 Example of an Asynchronous Iterator
我们可以探索如何使用“async for”表达式来遍历异步迭代器。
在此示例中,我们将更新前面的示例,以使用 “async for” 循环遍历迭代器直至完成。
此循环将自动等待从迭代器返回的每个等待,检索返回的值,并使其在循环体内可用,以便在这种情况下可以报告它。
这可能是异步迭代器最常见的使用模式。
下面列出了完整的示例。
# SuperFastPython.com
# 具有异步 for 循环的异步迭代器的示例
import asyncio
# 定义一个异步迭代器
class AsyncIterator():
# 构造函数,定义一些状态
def __init__(self):
self.counter = 0
# 创建迭代器的实例
def __aiter__(self):
return self
# 返回下一个可等待对象
async def __anext__(self):
# 检查没有其他项目
if self.counter >= 10:
raise StopAsyncIteration
# 增加计数器
self.counter += 1
# 模拟工作
await asyncio.sleep(1)
# 返回计数器值
return self.counter
# 主协程
async def main():
# 使用 async for 循环遍历异步迭代器
async for item in AsyncIterator():
print(item)
# 执行异步程序
asyncio.run(main())
运行该示例首先创建 main() 协程,并将其用作 asyncio 程序的入口点。
main() 协程运行并启动 for 循环。
创建异步迭代器的实例,循环使用 anext() 函数自动步进它以返回可等待的对象。 然后,循环等待可等待对象并检索一个值,该值可供报告该值的循环体使用。
然后重复这个过程,挂起 main() 协程,执行迭代器的一个步骤并挂起,然后恢复 main() 协程,直到迭代器耗尽。
一旦迭代器的内部计数器达到 10,就会引发 StopAsyncIteration。 这不会终止程序。 相反,它是由 “async for” 表达式期望和处理的,并打破循环。
这突出显示了如何使用 async for 表达式遍历异步迭代器。
1
2
3
4
5
6
7
8
9
10
您可以在教程中了解有关异步迭代器的更多信息:
接下来,我们将探索异步生成器。
We can explore how to traverse an asynchronous iterator using the “async for” expression.
In this example, we will update the previous example to traverse the iterator to completion using an “async for” loop.
This loop will automatically await each awaitable returned from the iterator, retrieve the returned 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 iterators.
The complete example is listed below.
# SuperFastPython.com
# example of an asynchronous iterator with async for loop
import asyncio
# define an asynchronous iterator
class AsyncIterator():
# constructor, define some state
def __init__(self):
self.counter = 0
# create an instance of the iterator
def __aiter__(self):
return self
# return the next awaitable
async def __anext__(self):
# check for no further items
if self.counter >= 10:
raise StopAsyncIteration
# increment the counter
self.counter += 1
# simulate work
await asyncio.sleep(1)
# return the counter value
return self.counter
# main coroutine
async def main():
# loop over async iterator with async for loop
async for item in AsyncIterator():
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 iterator 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 a step of the iterator and suspending, and resuming the main() coroutine until the iterator is exhausted.
Once the internal counter of the iterator reaches 10, a StopAsyncIteration is raised. This does not terminate the program. Instead, it is expected and handled by the “async for” expression and breaks the loop.
This highlights how an asynchronous iterator can be traversed using an async for expression.
1
2
3
4
5
6
7
8
9
10
You can learn more about async iterators in the tutorial:
Next, we will explore asynchronous generators.
创建日期: 2024年9月4日