动动发财的小手,点个赞吧!
本节答复开发人员在 Python 中应用 asyncio 时提出的常见问题。
6. 正在运行的工作是否会阻止事件循环退出?
不会!
独立调度和运行的工作不会阻止事件循环退出。如果你的主协程没有其余流动要实现并且有独立的工作在后盾运行,你应该检索正在运行的工作并期待它们
7. 如何显示正在运行的工作的进度?
咱们能够在每个工作上应用 done 回调函数来显示进度。实现回调是咱们能够在 asyncio.Task 上注册的函数。
一旦工作实现,它就会被调用,无论是失常还是失败。done 回调函数是一个惯例函数,而不是协程,并将与其关联的 asyncio.Task 作为参数。咱们能够对所有工作应用雷同的回调函数并以通用形式报告进度,例如通过报告音讯。
# callback function to show progress of tasks
def progress(task):
# report progress of the task
print('.', end='')
咱们能够在咱们收回的每个 asyncio.Task 上注册一个回调函数。这能够通过在每个工作上应用 add_done_callback() 办法并将回调函数的名称传递给它来实现。
...
# add a done callback to a task
task.add_done_callback(progress)
8. 如何在提早后运行工作?
咱们能够开发一个自定义包装器协程来在提早后执行指标协程。包装协程可能有两个参数,一个协程和一个以秒为单位的工夫。它将在给定的提早距离内休眠(以秒为单位),而后期待提供的协程。上面的 delay() 协程实现了这一点。
# coroutine that will start another coroutine after a delay in seconds
async def delay(coro, seconds):
# suspend for a time limit in seconds
await asyncio.sleep(seconds)
# execute the other coroutine
await coro
要应用包装协程,能够创立协程对象并间接期待或作为工作独立执行。例如,调用者能够挂起并调度提早协程并期待它实现:
...
# execute a coroutine after a delay
await delay(coro, 10)
或者,调用者能够安顿提早协程独立运行:
...
# execute a coroutine after a delay independently
_ = asyncio.create_task(delay(coro, 10))
9. 如何运行后续工作?
asyncio 中次要有 3 种形式来公布后续工作:
- 从已实现的工作自身安顿后续工作。
- 安顿呼叫者的后续工作。
- 应用实现回调主动安顿后续工作。
实现的工作能够公布本人的后续工作。这可能须要查看一些状态以确定是否应该收回后续工作。而后能够通过调用 asyncio.create_task() 来安顿工作。
...
# schedule a follow-up task
task = asyncio.create_task(followup_task())
工作自身能够抉择期待后续工作,也能够让其在后盾独立实现。
...
# wait for the follow-up task to complete
await task
收回工作的调用者能够抉择收回后续工作。例如,当调用者收回第一个工作时,它可能会保留 asyncio.Task 对象。而后它能够查看工作的后果或工作是否胜利实现。而后调用者能够决定收回后续工作。它可能会也可能不会间接期待后续工作。
...
# issue and await the first task
task = await asyncio.create_task(task())
# check the result of the task
if task.result():
# issue the follow-up task
followup = await asyncio.create_task(followup_task())
咱们能够应用 done 回调函数主动执行后续工作。例如,收回工作的调用者能够在工作自身上注册一个实现的回调函数。done 回调函数必须将 asyncio.Task 对象作为参数,并且只有在工作实现后才会被调用。而后它能够抉择公布后续工作。done 回调函数是一个一般的 Python 函数,不是协程,所以不能期待后续工作
例如,回调函数可能如下所示:
# callback function
def callback(task):
# schedule and await the follow-up task
_ = asyncio.create_task(followup())
调用者能够收回第一个工作并注册实现的回调函数。
...
# schedule and the task
task = asyncio.create_task(work())
# add the done callback function
task.add_done_callback(callback)
10. 如何执行阻塞 I/O 或 CPU 绑定函数?
asyncio 模块提供了两种在 asyncio 程序中执行阻塞调用的办法。第一种是应用 asyncio.to_thread() 函数。这是在高级 API 中,供给用程序开发人员应用。asyncio.to_thread() 函数采纳要执行的函数名和任何参数。该函数在独自的线程中执行。它返回一个能够作为独立工作期待或安顿的协程。
...
# execute a function in a separate thread
await asyncio.to_thread(task)
在返回的协程有机会在事件循环中运行之前,工作不会开始执行。asyncio.to_thread() 函数在后盾创立一个 ThreadPoolExecutor 来执行阻塞调用。因而,asyncio.to_thread() 函数仅实用于 IO 绑定工作。
另一种办法是应用 loop.run_in_executor() 函数。这是在低级异步 API 中,首先须要拜访事件循环,例如通过 asyncio.get_running_loop() 函数。loop.run_in_executor() 函数承受一个执行器和一个要执行的函数。
如果没有为执行器提供,则应用默认执行器,即 ThreadPoolExecutor。loop.run_in_executor() 函数返回一个可期待对象,如果须要能够期待它。工作将立刻开始执行,因而返回的可期待对象不须要期待或安顿阻塞调用开始执行。
...
# get the event loop
loop = asyncio.get_running_loop()
# execute a function in a separate thread
await loop.run_in_executor(None, task)
或者,能够创立一个执行器并将其传递给 loop.run_in_executor() 函数,该函数将在执行器中执行异步调用。
在这种状况下,调用者必须治理执行器,一旦调用者实现它就将其敞开。
...
# create a process pool
with ProcessPoolExecutor as exe:
# get the event loop
loop = asyncio.get_running_loop()
# execute a function in a separate thread
await loop.run_in_executor(exe, task)
# process pool is shutdown automatically...
这两种办法容许阻塞调用作为异步工作在 asyncio 程序中执行。
本文由 mdnice 多平台公布