12. 等待任务的集合¶
12. Wait for A Collection of Tasks
我们可以通过 asyncio.wait() 函数等待 asyncio 任务完成。
可以等待不同的条件,例如所有任务完成、第一个任务完成、第一个任务因异常而失败。
让我们仔细看看。
We can wait for asyncio tasks to complete via the asyncio.wait() function.
Different conditions can be waited for, such as all tasks to complete, the first task to complete, and the first task to fail with an exception.
Let’s take a closer look.
12.1 什么是 asyncio.wait()¶
12.1 What is asyncio.wait()
asyncio.wait() 函数可用于等待异步任务集合完成。
回想一下,asyncio 任务是包装协程的 asyncio.Task 类的实例。 它允许协程独立地调度和执行,并且 Task 实例提供任务的句柄用于查询状态和获取结果。
您可以在教程中了解有关异步任务的更多信息:
wait() 函数允许我们等待一组任务完成。
对 wait 的调用可以配置为等待不同的条件,例如所有任务都已完成、第一个任务已完成以及第一个任务因错误而失败。
接下来,让我们看看如何使用 wait() 函数。
The asyncio.wait() function can be used to wait for a collection of asyncio tasks to complete.
Recall that an asyncio task is an instance of the asyncio.Task class that wraps a coroutine. It allows a coroutine to be scheduled and executed independently, and the Task instance provides a handle on the task for querying status and getting results.
You can learn more about asyncio tasks in the tutorial:
The wait() function allows us to wait for a collection of tasks to be done.
The call to wait can be configured to wait for different conditions, such as all tasks being completed, the first task completed and the first task failing with an error.
Next, let’s look at how we might use the wait() function.
12.2 如何使用 asyncio.wait()¶
12.2 How to Use asyncio.wait()
asyncio.wait() 函数采用可等待对象的集合,通常是 Task 对象。
这可以是我们创建的任务对象的list、dict或set,例如通过调用列表推导式中的 asyncio.create_task() 函数 。
例如:
...
# 创建许多任务
tasks = [asyncio.create_task(task_coro(i)) for i in range(10)]
在满足任务集合的某些条件之前, asyncio.wait() 将不会返回。
默认情况下,条件是所有任务均已完成。
wait() 函数返回两个集合的元组。 第一个集合包含满足条件的所有任务对象,第二个集合包含尚未满足条件的所有其他任务对象。
这些集称为 “done” 集和 “pending” 集。
例如:
...
# 等待所有任务完成
done, pending = await asyncio.wait(tasks)
从技术上讲, asyncio.wait() 是一个返回协程的协程函数。
然后我们可以等待这个协程,它将返回集合的元组。
例如:
...
# 创建等待协程
wait_coro = asyncio.wait(tasks)
# 等待协程
tuple = await wait_coro
等待的条件可以通过 “return_when” 参数指定,默认设置为 asyncio.ALL_COMPLETED。
例如:
...
# 等待所有任务完成
done, pending = await asyncio.wait(tasks, return_when=asyncio.ALL_COMPLETED)
我们可以通过将 return_when 设置为 FIRST_COMPLETED 来等待第一个任务完成。
例如:
...
# 等待第一个任务完成
done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
当第一个任务完成并返回完成集中时,其余任务不会取消并继续并发执行。
我们可以通过将 return_when 设置为 FIRST_EXCEPTION 来等待第一个任务因异常而失败。
例如:
...
# 等待第一个任务失败
done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION)
在这种情况下,完成集将包含第一个因异常而失败的任务。 如果没有任务因异常而失败,则完成集将包含所有任务,并且 wait() 仅在所有任务完成后才返回。
我们可以通过 “timeout” 参数指定我们愿意等待给定条件的时间(以秒为单位)。
如果在满足条件之前超时到期,则返回任务元组以及当时满足条件的任何任务子集,例如 如果等待所有任务完成,则为完成的任务子集。
例如:
...
# 等待所有任务完成并使用超时
done, pending = await asyncio.wait(tasks, timeout=3)
如果在满足条件之前达到超时,则不会引发异常,并且不会取消剩余的任务。
现在我们知道如何使用 asyncio.wait() 函数,让我们看一些有效的示例。
The asyncio.wait() function takes a collection of awaitables, typically Task objects.
This could be a list, dict, or set of task objects that we have created, such as via calls to the asyncio.create_task() function in a list comprehension.
For example:
...
# create many tasks
tasks = [asyncio.create_task(task_coro(i)) for i in range(10)]
The asyncio.wait() will not return until some condition on the collection of tasks is met.
By default, the condition is that all tasks are completed.
The wait() function returns a tuple of two sets. The first set contains all task objects that meet the condition, and the second contains all other task objects that do not yet meet the condition.
These sets are referred to as the “done” set and the “pending” set.
For example:
...
# wait for all tasks to complete
done, pending = await asyncio.wait(tasks)
Technically, the asyncio.wait() is a coroutine function that returns a coroutine.
We can then await this coroutine which will return the tuple of sets.
For example:
...
# create the wait coroutine
wait_coro = asyncio.wait(tasks)
# await the wait coroutine
tuple = await wait_coro
The condition waited for can be specified by the “return_when” argument which is set to asyncio.ALL_COMPLETED by default.
For example:
...
# wait for all tasks to complete
done, pending = await asyncio.wait(tasks, return_when=asyncio.ALL_COMPLETED)
We can wait for the first task to be completed by setting return_when to FIRST_COMPLETED.
For example:
...
# wait for the first task to be completed
done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
When the first task is complete and returned in the done set, the remaining tasks are not canceled and continue to execute concurrently.
We can wait for the first task to fail with an exception by setting return_when to FIRST_EXCEPTION.
For example:
...
# wait for the first task to fail
done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION)
In this case, the done set will contain the first task that failed with an exception. If no task fails with an exception, the done set will contain all tasks and wait() will return only after all tasks are completed.
We can specify how long we are willing to wait for the given condition via a “timeout” argument in seconds.
If the timeout expires before the condition is met, the tuple of tasks is returned with whatever subset of tasks do meet the condition at that time, e.g. the subset of tasks that are completed if waiting for all tasks to complete.
For example:
...
# wait for all tasks to complete with a timeout
done, pending = await asyncio.wait(tasks, timeout=3)
If the timeout is reached before the condition is met, an exception is not raised and the remaining tasks are not canceled.
Now that we know how to use the asyncio.wait() function, let’s look at some worked examples.
12.3 等待所有任务的示例¶
12.3 Example of Waiting for All Tasks
我们可以探索如何使用 asyncio.wait() 等待所有任务。
在此示例中,我们将定义一个简单的任务协程,它生成一个随机值,休眠一小会儿,然后报告包含生成值的消息。
然后,主协程将使用协程在列表推导中创建许多任务,然后等待所有任务完成。
下面列出了完整的示例。
# SuperFastPython.com
# 等待所有任务完成的示例
from random import random
import asyncio
# 在新任务中执行的协程
async def task_coro(arg):
# 生成 0 到 1 之间的随机值
value = random()
# 暂时阻塞
await asyncio.sleep(value)
# 报告值
print(f'>task {arg} done with {value}')
# 主协程
async def main():
# 创建许多任务
tasks = [asyncio.create_task(task_coro(i)) for i in range(10)]
# 等待所有任务完成
done,pending = await asyncio.wait(tasks)
# 报告结果
print('All done')
# 启动异步程序
asyncio.run(main())
运行该示例首先创建 main() 协程,并将其用作 asyncio 程序的入口点。
然后,main() 协程在列表理解中创建一个包含十个任务的列表,每个任务提供一个从 0 到 9 的唯一整数参数。
然后 main() 协程被挂起并等待所有任务完成。
任务执行。 每个生成一个随机值,休眠一会儿,然后报告其生成的值。
所有任务完成后,main() 协程恢复并报告最终消息。
此示例重点介绍了如何使用 wait() 函数来等待任务集合完成。
这可能是该函数最常见的用法。
请注意,由于使用随机数,每次运行程序时结果都会有所不同。
>task 5 done with 0.0591009105682192
>task 8 done with 0.10453715687017351
>task 0 done with 0.15462838864295925
>task 6 done with 0.4103492027393125
>task 9 done with 0.45567100006991623
>task 2 done with 0.6984682905809402
>task 7 done with 0.7785363531316224
>task 3 done with 0.827386088873161
>task 4 done with 0.9481344994700972
>task 1 done with 0.9577302665040541
All done
您可以在教程中了解有关 wait() 函数的更多信息:
接下来,我们将探讨如何在有时间限制的情况下等待单个协程。
We can explore how to wait for all tasks using asyncio.wait().
In this example, we will define a simple task coroutine that generates a random value, sleeps for a fraction of a second, then reports a message with the generated value.
The main coroutine will then create many tasks in a list comprehension with the coroutine and then wait for all tasks to be completed.
The complete example is listed below.
# SuperFastPython.com
# example of waiting for all tasks to complete
from random import random
import asyncio
# coroutine to execute in a new task
async def task_coro(arg):
# generate a random value between 0 and 1
value = random()
# block for a moment
await asyncio.sleep(value)
# report the value
print(f'>task {arg} done with {value}')
# main coroutine
async def main():
# create many tasks
tasks = [asyncio.create_task(task_coro(i)) for i in range(10)]
# wait for all tasks to complete
done,pending = await asyncio.wait(tasks)
# report results
print('All done')
# start 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 then creates a list of ten tasks in a list comprehension, each providing a unique integer argument from 0 to 9.
The main() coroutine is then suspended and waits for all tasks to complete.
The tasks execute. Each generates a random value, sleeps for a moment, then reports its generated value.
After all tasks have been completed, the main() coroutine resumes and reports a final message.
This example highlights how we can use the wait() function to wait for a collection of tasks to be completed.
This is perhaps the most common usage of the function.
Note, that the results will differ each time the program is run given the use of random numbers.
>task 5 done with 0.0591009105682192
>task 8 done with 0.10453715687017351
>task 0 done with 0.15462838864295925
>task 6 done with 0.4103492027393125
>task 9 done with 0.45567100006991623
>task 2 done with 0.6984682905809402
>task 7 done with 0.7785363531316224
>task 3 done with 0.827386088873161
>task 4 done with 0.9481344994700972
>task 1 done with 0.9577302665040541
All done
You can learn more about the wait() function in the tutorial:
Next, we will explore how to wait for a single coroutine with a time limit.
创建日期: 2024年9月4日