13. 等待有时间限制的协程¶
13. Wait for a Coroutine with a Time Limit
我们可以使用 asyncio.wait_for() 函数等待 asyncio 任务或协程完成并超时。
如果在任务完成之前超时,则任务将被取消。
让我们仔细看看。
We can wait for an asyncio task or coroutine to complete with a timeout using the asyncio.wait_for() function.
If the timeout elapses before the task completes, the task is canceled.
Let’s take a closer look.
13.1 什么是 Asyncio wait_for()¶
13.1 What is Asyncio wait_for()
asyncio.wait_for() 函数允许调用者等待异步任务或协程完成并超时。
如果没有指定超时,wait_for()函数将等待,直到任务完成。
如果指定了超时并在任务完成之前超时,则任务将被取消。
等待 aw waitable 完成并超时。
这允许调用者设置他们愿意等待任务完成多长时间的期望,并在超时结束时通过取消任务来强制超时。
现在我们知道了 asyncio.wait_for() 函数是什么,让我们看看如何使用它。
The asyncio.wait_for() function allows the caller to wait for an asyncio task or coroutine to complete with a timeout.
If no timeout is specified, the wait_for() function will wait until the task is completed.
If a timeout is specified and elapses before the task is complete, then the task is canceled.
Wait for the aw awaitable to complete with a timeout.
This allows the caller to both set an expectation about how long they are willing to wait for a task to complete, and to enforce the timeout by canceling the task if the timeout elapses.
Now that we know what the asyncio.wait_for() function is, let’s look at how to use it.
13.2 如何使用 Asyncio wait_for()¶
13.2 How to Use Asyncio wait_for()
asyncio.wait_for() 函数需要等待和超时。
可等待的可能是协程或任务。
必须指定超时,并且可以为 None(无超时)、整数或浮点数秒数。
wait_for() 函数返回一个协程,该协程在被显式等待或安排为任务之前不会执行。
例如:
...
# 等待任务完成
await asyncio.wait_for(coro, timeout=10)
如果提供了协程,则会在执行 wait_for() 协程时将其转换为任务。
如果在任务完成之前超时,任务将被取消,并引发 asyncio.TimeoutError,这可能需要处理。
例如:
...
# 执行超时任务
try:
# 等待任务完成
await asyncio.wait_for(coro, timeout=1)
except asyncio.TimeoutError:
# ...
如果等待的任务因未处理的异常而失败,则该异常将传播回正在等待 wait_for() 协程的调用者,在这种情况下可能需要对其进行处理。
例如:
...
# 执行可能失败的任务
try:
# 等待任务完成
await asyncio.wait_for(coro, timeout=1)
except asyncio.TimeoutError:
# ...
except Exception:
# ...
接下来,让我们看看如何调用 wait_for() 并设置超时。
The asyncio.wait_for() function takes an awaitable and a timeout.
The awaitable may be a coroutine or a task.
A timeout must be specified and may be None for no timeout, an integer or floating point number of seconds.
The wait_for() function returns a coroutine that is not executed until it is explicitly awaited or scheduled as a task.
For example:
...
# wait for a task to complete
await asyncio.wait_for(coro, timeout=10)
If a coroutine is provided, it will be converted to the task when the wait_for() coroutine is executed.
If the timeout elapses before the task is completed, the task is canceled, and an asyncio.TimeoutError is raised, which may need to be handled.
For example:
...
# execute a task with a timeout
try:
# wait for a task to complete
await asyncio.wait_for(coro, timeout=1)
except asyncio.TimeoutError:
# ...
If the waited-for task fails with an unhandled exception, the exception will be propagated back to the caller that is awaiting on the wait_for() coroutine, in which case it may need to be handled.
For example
...
# execute a task that may fail
try:
# wait for a task to complete
await asyncio.wait_for(coro, timeout=1)
except asyncio.TimeoutError:
# ...
except Exception:
# ...
Next, let’s look at how we can call wait_for() with a timeout.
13.3 带有超时的 Asyncio wait_for() 示例¶
13.3 Example of Asyncio wait_for() With a Timeout
我们可以探索如何在任务完成之前等待超时的协程。
在这个例子中,我们像上面一样执行一个协程,除了调用者等待 0.2 秒或 200 毫秒的固定超时。
回想一下,一秒等于 1,000 毫秒。
任务协程经过修改,使其休眠时间超过一秒,确保超时始终在任务完成之前到期。
下面列出了完整的示例。
# SuperFastPython.com
# 等待超时协程的示例
from random import random
import asyncio
# 在新任务中执行的协程
async def task_coro(arg):
# 生成 0 到 1 之间的随机值
value = 1 + random()
# 报告消息
print(f'>task got {value}')
# 阻塞片刻
await asyncio.sleep(value)
# 报告所有已完成
print('>task done')
# 主协程
async def main():
# 创建一个任务
task = task_coro(1)
# 执行并等待任务,无超时
try:
await asyncio.wait_for(task, timeout=0.2)
except asyncio.TimeoutError:
print('Gave up waiting, task canceled')
# 开始异步程序
asyncio.run(main())
运行该示例首先创建 main() 协程,并将其用作 asyncio 程序的入口点。
main() 协程创建任务协程。 然后,它调用 wait_for() 并传递任务协程并将超时设置为 0.2 秒。
main() 协程被挂起并执行 task_coro()。 它报告一条消息并休眠一会儿。
main() 协程在超时后恢复。 wait_for() 协程取消 task_coro() 协程,并且 main() 协程被挂起。
task_coro() 再次运行并响应要终止的请求。 它引发 TimeoutError 异常并终止。
main() 协程恢复并处理由 task_coro() 引发的 TimeoutError。
这强调了我们如何调用带有超时的 wait_for() 函数,并在超时内未完成任务时取消任务。
由于使用随机数,程序每次运行时的输出都会有所不同。
>task got 0.685375224799321
Gave up waiting, task canceled
您可以在教程中了解有关 wait_for() 函数的更多信息:
接下来,我们将探讨如何保护异步任务不被取消。
We can explore how to wait for a coroutine with a timeout that elapses before the task is completed.
In this example, we execute a coroutine as above, except the caller waits a fixed timeout of 0.2 seconds or 200 milliseconds.
Recall that one second is equal to 1,000 milliseconds.
The task coroutine is modified so that it sleeps for more than one second, ensuring that the timeout always expires before the task is complete.
The complete example is listed below.
# SuperFastPython.com
# example of waiting for a coroutine with a timeout
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 = 1 + random()
# report message
print(f'>task got {value}')
# block for a moment
await asyncio.sleep(value)
# report all done
print('>task done')
# main coroutine
async def main():
# create a task
task = task_coro(1)
# execute and wait for the task without a timeout
try:
await asyncio.wait_for(task, timeout=0.2)
except asyncio.TimeoutError:
print('Gave up waiting, task canceled')
# 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 creates the task coroutine. It then calls wait_for() and passes the task coroutine and sets the timeout to 0.2 seconds.
The main() coroutine is suspended and the task_coro() is executed. It reports a message and sleeps for a moment.
The main() coroutine resumes after the timeout has elapsed. The wait_for() coroutine cancels the task_coro() coroutine and the main() coroutine is suspended.
The task_coro() runs again and responds to the request to be terminated. It raises a TimeoutError exception and terminates.
The main() coroutine resumes and handles the TimeoutError raised by the task_coro().
This highlights how we can call the wait_for() function with a timeout and to cancel a task if it is not completed within a timeout.
The output from the program will differ each time it is run given the use of random numbers.
>task got 0.685375224799321
Gave up waiting, task canceled
You can learn more about the wait_for() function in the tutorial:
Next, we will explore how we might protect an asyncio task from being canceled.
创建日期: 2024年9月4日