乐趣区

关于程序员:Python-异步-常见问题-Part123

动动发财的小手,点个赞吧!

本节答复开发人员在 Python 中应用 asyncio 时提出的常见问题。

1. 如何进行工作?

咱们能够通过 asyncio.Task 对象上的 cancel() 办法勾销工作。如果工作被勾销,cancel() 办法返回 True,否则返回 False。

...
# cancel the task
was_cancelled = task.cancel()

如果工作曾经实现,则无奈勾销,cancel() 办法将返回 False,工作不会处于已勾销状态。

下次工作有机会运行时,它将引发 CancelledError 异样。如果 CancelledError 异样未在包装协程内解决,工作将被勾销。

否则,如果在包装协程内解决了 CancelledError 异样,工作将不会被勾销。cancel() 办法还能够承受一个音讯参数,该参数将在 CancelledError 的内容中应用。

咱们能够摸索如何勾销正在运行的工作。

在这个例子中,咱们定义了一个工作协程,它报告一条音讯而后阻塞片刻。

而后咱们定义用作 asyncio 程序入口点的主协程。它报告一条音讯,创立并安顿工作,而后期待片刻。

而后主协程在运行时复原和勾销工作。它再等一会儿,让工作响应勾销申请。而后主协程报告勾销工作的申请是否胜利。

工作被勾销,而后实现。主协程而后在关闭程序之前报告工作的状态是否已勾销。

# SuperFastPython.com
# example of canceling a running task
import asyncio
 
# define a coroutine for a task
async def task_coroutine():
    # report a message
    print('executing the task')
    # block for a moment
    await asyncio.sleep(1)
 
# custom coroutine
async def main():
    # report a message
    print('main coroutine started')
    # create and schedule the task
    task = asyncio.create_task(task_coroutine())
    # wait a moment
    await asyncio.sleep(0.1)
    # cancel the task
    was_cancelled = task.cancel()
    # report whether the cancel request was successful
    print(f'was canceled: {was_cancelled}')
    # wait a moment
    await asyncio.sleep(0.1)
    # check the status of the task
    print(f'canceled: {task.cancelled()}')
    # report a final message
    print('main coroutine done')
 
# start the asyncio program
asyncio.run(main())

运行该示例会启动 asyncio 事件循环并执行 main() 协程。main() 协程报告一条音讯,而后创立并调度工作协程。而后它暂停并期待片刻以容许工作协程开始运行。工作运行,报告音讯并休眠一段时间。

main() 协程复原和勾销工作。它报告勾销工作的申请已胜利。而后它会休眠片刻,让工作响应要勾销的申请。

task_coroutine() 复原并引发 CancelledError 异样,导致工作失败并实现。main() 协程复原并报告工作是否处于勾销状态。在这种状况下,的确如此。

此示例突出显示了勾销正在运行的工作的失常状况。

main coroutine started
executing the task
was canceled: True
canceled: True
main coroutine done

2. 如何期待工作实现?

咱们能够通过间接期待 asyncio.Task 对象来期待工作实现。

...
# wait for the task to finish
await task

咱们能够在一行中创立和期待工作。

...
# create and wait for the task to finish
await asyncio.create_task(custom_coro())

3. 如何从工作中获取返回值?

咱们可能须要将协程的值返回给调用者。咱们能够通过期待从协程中检索返回值。它假设正在期待的另一个协程返回一个值。

# coroutine that returns a value
async def other_coro():
    return 100

期待其余协程将挂起调用协程并安顿其余协程执行。一旦另一个协程实现,调用协程将复原。返回值将从另一个协程传递给调用者。

...
# execute coroutine and retrieve return value
value = await other_coro()

协程能够包装在 asyncio.Task 对象中。这有助于独立执行协程而无需以后协程期待它。

这能够应用 asyncio.create_task() 函数来实现。

...
# wrap coroutine in a task and schedule it for execution
task = asyncio.create_task(other_coro())

有两种办法能够从 asyncio.Task 中检索返回值,它们是:

  • 期待工作。
  • 调用后果 () 办法。

咱们能够期待工作来检索返回值。如果工作已安顿或正在运行,则调用者将挂起,直到工作实现并提供返回值。如果工作实现,将立刻提供返回值。

...
# get the return value from a task
value = await task

与协程不同,咱们能够屡次期待工作而不会引发谬误。

...
# get the return value from a task
value = await task
# get the return value from a task
value = await task

咱们还能够通过调用 asyncio.Task 对象的 result() 办法来获取工作的返回值。

...
# get the return value from a task
value = task.result()

这须要实现工作。如果不是,将引发 InvalidStateError 异样。如果工作被勾销,将引发 CancelledError 异样。

4. 如何在后盾运行工作?

咱们能够通过将协程包装在 asyncio.Task 对象中来在后盾运行协程。这能够通过调用 asyncio.create_task() 函数并将其传递给协程来实现。

协程将被包装在一个 Task 对象中,并被安顿执行。将返回工作对象,调用者不会挂起。

...
# schedule the task for execution
task = asyncio.create_task(other_coroutine())

至多在以后协程出于任何起因挂起之前,工作不会开始执行。咱们能够通过暂停片刻让工作开始运行来帮忙解决问题。这能够通过休眠零秒来实现。

...
# suspend for a moment to allow the task to start running
await asyncio.sleep(0)

这将暂停调用者一小会儿,并容许申请运行的机会。这不是必须的,因为调用者可能会在将来某个工夫暂停或作为失常执行的一部分终止。一旦调用者没有事件要做,咱们也能够间接期待工作。

...
# wait for the task to complete
await task

5. 如何期待所有后台任务?

咱们能够期待 asyncio 程序中的所有独立工作。这能够通过首先通过 asyncio.all_tasks() 函数获取一组所有以后正在运行的工作来实现。

...
# get a set of all running tasks
all_tasks = asyncio.all_tasks()

这将返回一个汇合,其中蕴含一个 asyncio.Task 对象,用于以后正在运行的每个工作,包含 main() 协程。

咱们不能间接期待这个汇合,因为它会永远阻塞,因为它蕴含当前任务。因而,咱们能够获取以后正在运行的工作的 asyncio.Task 对象并将其从汇合中删除。

这能够通过首先调用 asyncio.current_task() 办法来获取以后协程的工作,而后通过 remove() 办法将其从汇合中删除来实现。

...
# get the current tasks
current_task = asyncio.current_task()
# remove the current task from the list of all tasks
all_tasks.remove(current_task)

最初,咱们能够期待残余的工作集。这将挂起调用者,直到汇合中的所有工作都实现。

...
# suspend until all tasks are completed
await asyncio.wait(all_tasks)

将它们联合在一起,上面增加到 main() 协程开端的代码片段将期待所有后台任务实现。

...
# get a set of all running tasks
all_tasks = asyncio.all_tasks()
# get the current tasks
current_task = asyncio.current_task()
# remove the current task from the list of all tasks
all_tasks.remove(current_task)
# suspend until all tasks are completed
await asyncio.wait(all_tasks)

本文由 mdnice 多平台公布

退出移动版