跳转至

24. Python Asyncio 常见问题

24. Python Asyncio Common Questions

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

您对 asyncio 有疑问吗?

在下面的评论中提出您的问题,我会尽力回答它,也许会将其添加到这个问题列表中。

This section answers common questions asked by developers when using asyncio in Python.

Do you have a question about asyncio?

Ask your question in the comments below and I will do my best to answer it and perhaps add it to this list of questions.

24.1 如何停止任务?

24.1 How to Stop a Task?

我们可以通过 asyncio.Task 对象上的 cancel() 方法取消任务。

如果任务被取消,则 cancel() 方法返回 True,否则返回 False

例如:

...
# 取消任务
was_cancelled = task.cancel()

如果任务已经完成,则无法取消,cancel() 方法将返回 False,任务不会处于已取消状态。

下次任务有机会运行时,它将引发 CancelledError 异常。

如果未在包装的协程内处理 CancelledError 异常,则任务将被取消。

否则,如果在包装的协程内处理 CancelledError 异常,则任务将不会被取消。

cancel() 方法同样还可以传递一个消息参数,作为 CancelledError 异常的内容。

我们可以探讨如何取消正在运行的任务。

在这个例子中,我们定义了一个任务协程,它报告一条消息,然后阻塞一会儿。

然后,我们定义用作 asyncio 程序入口点的主协程。 它报告一条消息,创建并安排任务,然后等待片刻。

然后,主协程在任务运行时恢复并取消任务。 它会再等待一段时间,以便任务响应取消请求。 然后主协程报告取消任务的请求是否成功。

任务被取消,然后完成。

然后主协程在关闭程序之前报告任务的状态是否已取消。

下面列出了完整的示例。

# SuperFastPython.com
# 取消一个正在运行的任务的例子
import asyncio

# 为任务定义一个协程
async def task_coroutine():
    # 报告一条消息
    print('executing the task')
    # 阻塞片刻
    await asyncio.sleep(1)

# 自定义协程
async def main():
    # 报告一条消息
    print('main coroutine started')
    # 创建并调度任务
    task = asyncio.create_task(task_coroutine())
    # 等待一下
    await asyncio.sleep(0.1)
    # 取消任务
    was_cancelled = task.cancel()
    # 报告取消请求是否成功
    print(f'was canceled: {was_cancelled}')
    # 等待一下
    await asyncio.sleep(0.1)
    # 检查任务的状态
    print(f'canceled: {task.cancelled()}')
    # 报告最后的消息
    print('main coroutine done')

# 启动异步程序
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

We can cancel a task via the cancel() method on an asyncio.Task object.

The cancel() method returns True if the task was canceled, or False otherwise.

For example:

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

If the task is already done, it cannot be canceled and the cancel() method will return False and the task will not have the status of canceled.

The next time the task is given an opportunity to run, it will raise a CancelledError exception.

If the CancelledError exception is not handled within the wrapped coroutine, the task will be canceled.

Otherwise, if the CancelledError exception is handled within the wrapped coroutine, the task will not be canceled.

The cancel() method can also take a message argument which will be used in the content of the CancelledError.

We can explore how to cancel a running task.

In this example, we define a task coroutine that reports a message and then blocks for a moment.

We then define the main coroutine that is used as the entry point into the asyncio program. It reports a message, creates and schedules the task, then waits a moment.

The main coroutine then resumes and cancels the task while it is running. It waits a moment more to allow the task to respond to the request to cancel. The main coroutine then reports whether the request to cancel the task was successful.

The task is canceled and is then done.

The main coroutine then reports whether the status of the task is canceled before closing the program.

The complete example is listed below.

# 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())

Running the example starts the asyncio event loop and executes the main() coroutine.

The main() coroutine reports a message, then creates and schedules the task coroutine.

It then suspends and awaits a moment to allow the task coroutine to begin running.

The task runs, reports a message and sleeps for a while.

The main() coroutine resumes and cancels the task. It reports that the request to cancel the task was successful.

It then sleeps for a moment to allow the task to respond to the request to be canceled.

The task_coroutine() resumes and a CancelledError exception is raised that causes the task to fail and be done.

The main() coroutine resumes and reports whether the task has the status of canceled. In this case, it does.

This example highlights the normal case of canceling a running task.

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

24.2 如何等待任务完成?

24.2 How to Wait for a Task To Finish?

我们可以通过直接等待 asyncio.Task 对象来等待任务完成。

例如:

...
# 等待任务完成
await task

我们可以在一行中创建并等待任务完成。

例如:

...
# 创建并等待任务完成
await asyncio.create_task(custom_coro())

We can wait for a task to finish by awaiting the asyncio.Task object directly.

For example:

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

We may create and wait for the task in a single line.

For example:

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

24.3 如何获取任务的返回值?

24.3 How to Get a Return Value from a Task?

我们可能需要将值从协程返回给调用者。

我们可以通过等待协程来检索返回值。

它假设正在等待的另一个协程返回一个值。

例如:

# 有返回值的协程
async def other_coro():
    return 100

等待另一个协程将挂起调用协程并安排另一个协程执行。 一旦其他协程完成,调用协程将恢复。 返回值将从另一个协程传递给调用者。

例如:

...
# 执行协程并获取返回值
value = await other_coro()

协程可以包装在 asyncio.Task 对象中。

这对于独立执行协程很有帮助,而无需当前协程等待它。

这可以使用 asyncio.create_task() 函数来实现。

例如:

...
# 将协程包装在任务中并安排其执行
task = asyncio.create_task(other_coro())

您可以在教程中了解有关如何创建任务的更多信息:

有两种方法可以从 asyncio.Task 中检索返回值,它们是:

  1. 等待任务.
  2. 调用 result() 方法.

我们可以等待任务来检索返回值。

如果任务已调度或正在运行,则调用者将挂起,直到任务完成并提供返回值。

如果任务完成,将立即提供返回值。

例如:

...
# 获取任务的返回值
value = await task

与协程不同,我们可以多次等待任务而不会引发错误。

例如:

...
# 获取任务的返回值
value = await task
# 获取任务的返回值
value = await task

我们还可以通过调用 asyncio.Task 对象上的 result() 方法来获取任务的返回值。

例如:

...
# 获取任务的返回值
value = task.result()

这就要求任务完成。 如果不是,将引发 InvalidStateError 异常。

如果任务被取消,则会引发 CancelledError 异常。

您可以了解有关从教程中的任务获取结果的更多信息:

We may need to return values from coroutines to the caller.

We can retrieve a return value from a coroutine by awaiting it.

It assumes that the other coroutine being awaited returns a value.

For example:

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

Awaiting the other coroutine will suspend the calling coroutine and schedule the other coroutine for execution. Once the other coroutine has been completed, the calling coroutine will resume. The return value will be passed from the other coroutine to the caller.

For example:

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

A coroutine can be wrapped in an asyncio.Task object.

This is helpful for independently executing the coroutine without having the current coroutine await it.

This can be achieved using the asyncio.create_task() function.

For example:

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

You can learn more about how to create tasks in the tutorial:

There are two ways to retrieve the return value from an asyncio.Task, they are:

  1. Await the task.
  2. Call the result() method.

We can await the task to retrieve the return value.

If the task is scheduled or running, then the caller will suspend until the task is complete and the return value will be provided.

If the task is completed, the return value will be provided immediately.

For example:

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

Unlike a coroutine, we can await a task more than once without raising an error.

For example:

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

We can also get the return value from the task by calling the result() method on the asyncio.Task object.

For example:

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

This requires that the task is done. If not, an InvalidStateError exception will be raised.

If the task was canceled a CancelledError exception will be raised.

You can learn more about getting the result from tasks in the tutorial:

24.4 如何在后台运行任务?

24.4 How to Run a Task in the Background?

我们可以通过将协程包装在 asyncio.Task 对象中来在后台运行协程。

这可以通过调用 asyncio.create_task() 函数并向其传递协程来实现。

协程将被包装在 Task 对象中并被安排执行。 任务对象将被返回,并且调用者不会挂起。

例如:

...
# 调度任务执行
task = asyncio.create_task(other_coroutine())

至少在当前协程出于任何原因被挂起之前,该任务不会开始执行。

我们可以通过暂停片刻以允许任务开始运行来帮助完成任务。

这可以通过休眠零秒来实现。

例如:

...
# 暂停片刻以允许任务开始运行
await asyncio.sleep(0)

这只会将调用者暂停一小会儿,并允许有机会运行。

这不是必需的,因为调用者可能会在将来的某个时间挂起或作为正常执行的一部分终止。

一旦调用者没有事情可做,我们也可以直接等待任务。

例如:

...
# 等待任务完成
await task

We can run a coroutine in the background by wrapping it in an asyncio.Task object.

This can be achieved by calling the asyncio.create_task() function and passing it the coroutine.

The coroutine will be wrapped in a Task object and will be scheduled for execution. The task object will be returned and the caller will not suspend.

For example:

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

The task will not begin executing until at least the current coroutine is suspended, for any reason.

We can help things along by suspending for a moment to allow the task to start running.

This can be achieved by sleeping for zero seconds.

For example:

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

This will suspend the caller only for a brief moment and allow the ask an opportunity to run.

This is not required as the caller may suspend at some future time or terminate as part of normal execution.

We may also await the task directly once the caller has run out of things to do.

For example:

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

24.5 如何等待所有后台任务?

24.5 How to Wait for All Background Tasks?

我们可以等待 asyncio 程序中的所有独立任务。

首先可以通过 asyncio.all_tasks() 函数获取一组所有当前正在运行的任务来实现。

例如:

...
# 获取所有正在运行的任务的集合
all_tasks = asyncio.all_tasks()

这将返回一个集合,其中包含当前正在运行的每个任务的一个 asyncio.Task 对象,包括 main() 协程。

我们不能直接等待这个集合,因为它会永远阻塞,因为它包含当前任务的任务。

因此,我们可以获取当前正在运行的任务的 asyncio.Task 对象并将其从集合中删除。

这首先可以通过调用 asyncio.current_task() 方法来获取当前协程的任务,然后通过 remove() 方法将其从集合中删除来实现。

例如:

...
# 获取当前任务
current_task = asyncio.current_task()
# 从所有任务列表中删除当前任务
all_tasks.remove(current_task)

最后,我们可以等待剩余的任务集。

这将挂起调用者,直到该组中的所有任务完成。

例如:

...
# 挂起直到所有任务完成
await asyncio.wait(all_tasks)

将它们结合在一起,添加到 main() 协程末尾的下面的代码片段将等待所有后台任务完成。

...
# 获取所有正在运行的任务的集合
all_tasks = asyncio.all_tasks()
# 获取当前任务
current_task = asyncio.current_task()
# 从所有任务列表中删除当前任务
all_tasks.remove(current_task)
# 挂起直到所有任务完成
await asyncio.wait(all_tasks)

We can wait for all independent tasks in an asyncio program.

This can be achieved by first getting a set of all currently running tasks via the asyncio.all_tasks() function.

For example:

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

This will return a set that contains one asyncio.Task object for each task that is currently running, including the main() coroutine.

We cannot wait on this set directly, as it will block forever as it includes the task that is the current task.

Therefore we can get the asyncio.Task object for the currently running task and remove it from the set.

This can be achieved by first calling the asyncio.current_task() method to get the task for the current coroutine and then remove it from the set via the remove() method.

For example:

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

Finally, we can wait on the set of remaining tasks.

This will suspend the caller until all tasks in the set are complete.

For example:

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

Tying this together, the snippet below added to the end of the main() coroutine will wait for all background tasks to complete.

...
# 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)

24.6 正在运行的任务是否会阻止事件循环退出?

24.6 Does a Running Task Stop the Event Loop from Exiting?

不。

独立调度和运行的任务不会阻止事件循环退出。

如果您的主协程没有其他活动需要完成,并且有独立任务在后台运行,您应该检索正在运行的任务并等待它们

上一个问题/答案准确地展示了如何做到这一点。

No.

A task that is scheduled and run independently will not stop the event loop from exiting.

If your main coroutine has no other activities to complete and there are independent tasks running in the background, you should retrieve the running tasks and wait on them

The previous question/answer shows exactly how to do this.

24.7 如何显示运行任务的进度?

24.7 How to Show Progress of Running Tasks?

我们可以使用每个任务的回调函数来显示进度。

执行完成后的回调函数是我们可以在 asyncio.Task 上注册的函数。

一旦任务执行完,无论正常还是失败,都会调用它。

done 回调函数是一个常规函数,而不是协程,并且将与其关联的 asyncio.Task 作为参数。

我们可以对所有任务使用相同的回调函数,并以通用方式报告进度,例如报告消息。

例如:

# 回调函数显示任务进度
def progress(task):
    # 报告任务进度
    print('.', end='')

我们可以在我们发出的每个 asyncio.Task 上注册一个回调函数。

这可以通过在每个任务上使用 add_done_callback() 方法并向其传递回调函数的名称来实现。

例如:

...
# 向任务添加回调函数
task.add_done_callback(progress)

We can show progress using a done callback function on each task.

A done callback is a function that we can register on an asyncio.Task.

It is called once the task is done, either normally or if it fails.

The done callback function is a regular function, not a coroutine, and takes the asyncio.Task that it is associated with as an argument.

We can use the same callback function for all tasks and report progress in a general way, such as by reporting a message.

For example:

# callback function to show progress of tasks
def progress(task):
    # report progress of the task
    print('.', end='')

We can register a callback function on each asyncio.Task that we issue.

This can be achieved using the add_done_callback() method on each task and passing it the name of the callback function.

For example:

...
# add a done callback to a task
task.add_done_callback(progress)

24.8 如何在延迟后运行任务?

24.8 How to Run a Task After a Delay?

我们可以开发一个自定义包装协程来在延迟后执行目标协程。

包装协程可以采用两个参数,一个协程和一个以秒为单位的时间。

它将休眠给定的延迟间隔(以秒为单位),然后等待提供的协程执行完毕。

下面的 delay() 协程实现了这一点。

# 延迟几秒后启动另一个协程的协程
async def delay(coro, seconds):
    # 暂停时间限制(以秒为单位)
    await asyncio.sleep(seconds)
    # 执行另一个协程
    await coro

要使用包装协程,可以创建协程对象并直接等待或作为任务独立执行。

例如,调用者可以挂起并调度延迟协程并等待其完成:

...
# 延迟后执行协程
await delay(coro, 10)

或者,调用者可以安排延迟协程独立运行:

...
# 在延迟后独立执行协程
_ = asyncio.create_task(delay(coro, 10))

We can develop a custom wrapper coroutine to execute a target coroutine after a delay.

The wrapper coroutine may take two arguments, a coroutine and a time in seconds.

It will sleep for the given delay interval in seconds, then await the provided coroutine.

The delay() coroutine below implements this.

# 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

To use the wrapper coroutine, a coroutine object can be created and either awaited directly or executed independently as a task.

For example, the caller may suspend and schedule the delayed coroutine and wait for it to be done:

...
# execute a coroutine after a delay
await delay(coro, 10)

Alternatively, the caller may schedule the delayed coroutine to run independently:

...
# execute a coroutine after a delay independently
_ = asyncio.create_task(delay(coro, 10))

24.9 如何运行后续任务?

24.9 How to Run a Follow-Up Task?

asyncio 中发出后续任务(follow-up tasks)的方式主要有三种。

他们是:

  1. 从已完成的任务本身调度后续任务。
  2. 从调用者调度后续任务。
  3. 使用回调函数自动调度后续任务。

让我们仔细看看每种方法。

完成的任务可以发出自己的后续任务。

这可能需要检查某些状态以确定是否应该发出后续任务。

然后可以通过调用 asyncio.create_task() 来安排任务 .

例如:

...
# schedule a follow-up task
task = asyncio.create_task(followup_task())

任务本身可以选择等待后续任务或让它在后台独立完成。

例如:

...
# 等待后续任务执行完毕
await task

下发任务的调用者可以选择下发后续任务。

例如,当调用者发出第一个任务时,它可能会保留 asyncio.Task 对象。

然后它可以检查任务的结果或任务是否成功完成。

然后调用者可以决定是否发出后续任务。

它也可以直接选择等待/不等待后续任务执行完毕。

例如:

...
# 发出并等待第一个任务
task = await asyncio.create_task(task())
# 检查任务结果
if task.result():
    # 下达后续任务
    followup = await asyncio.create_task(followup_task())

我们可以使用回调函数自动执行后续任务。

例如,发出任务的调用者可以在任务本身上注册执行完成后的回调函数。

回调函数必须将 asyncio.Task 对象作为参数,并且只有在任务完成后才会被调用。 然后它可以选择是否发出后续任务。

回调函数是一个常规的Python函数,而不是协程,因此它不能等待后续任务

例如,回调函数可能如下所示:

# 回调函数
def callback(task):
    # 调度并等待后续任务
    _ = asyncio.create_task(followup())

调用者可以发出第一个任务并注册执行完成后的回调函数。

例如:

...
# 调度任务
task = asyncio.create_task(work())
# 添加执行完后的回调函数
task.add_done_callback(callback)

There are three main ways to issue follow-up tasks in asyncio.

They are:

  1. Schedule the follow-up task from the completed task itself.
  2. Schedule the follow-up task from the caller.
  3. Schedule the follow-up task automatically using a done callback.

Let’s take a closer look at each approach.

The task that is completed can issue its own follow-up task.

This may require checking some state in order to determine whether the follow-up task should be issued or not.

The task can then be scheduled via a call to asyncio.create_task().

For example:

...
# schedule a follow-up task
task = asyncio.create_task(followup_task())

The task itself may choose to await the follow-up task or let it complete in the background independently.

For example:

...
# wait for the follow-up task to complete
await task

The caller that issued the task can choose to issue a follow-up task.

For example, when the caller issues the first task, it may keep the asyncio.Task object.

It can then check the result of the task or whether the task was completed successfully or not.

The caller can then decide to issue a follow-up task.

It may or may not await the follow-up task directly.

For example:

...
# 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())

We can execute a follow-up task automatically using a done callback function.

For example, the caller that issues the task can register a done callback function on the task itself.

The done callback function must take the asyncio.Task object as an argument and will be called only after the task is done. It can then choose to issue a follow-up task.

The done callback function is a regular Python function, not a coroutine, so it cannot await the follow-up task

For example, the callback function may look as follows:

# callback function
def callback(task):
    # schedule and await the follow-up task
    _ = asyncio.create_task(followup())

The caller can issue the first task and register the done callback function.

For example:

...
# schedule and the task
task = asyncio.create_task(work())
# add the done callback function
task.add_done_callback(callback)

24.10 如何在 Asyncio 中执行阻塞 I/O 或 CPU 密集型函数?

24.10 How to Execute a Blocking I/O or CPU-bound Function in Asyncio?

asyncio 模块提供了两种在 asyncio 程序中执行阻塞调用的方法。

第一种是使用 asyncio.to_thread() 函数。

这是高级 API 中的内容,适用于应用程序开发人员。

asyncio.to_thread() 函数接受要执行的函数名称和任何参数。

该函数在单独的线程中执行。 它返回一个可以作为独立任务等待或调度的协程。

例如:

...
# 在单独的线程中执行函数
await asyncio.to_thread(task)

任务一开始并不会执行。直到协程返回并且给个在事件循环中运行的机会时,才会运行。

asyncio.to_thread() 函数在后台创建一个 ThreadPoolExecutor 来执行阻塞调用。

因此,asyncio.to_thread() 函数仅适用于 IO 密集型任务。

另一种方法是使用loop.run_in_executor()函数。

这是在低级 asyncio API 中,首先需要访问事件循环,例如通过 asyncio.get_running_loop() 函数。

Loop.run_in_executor() 函数需要一个执行器和一个要执行的函数。

如果没有为执行器提供参数,则默认值为 None,将使用默认执行器,即 ThreadPoolExecutor

Loop.run_in_executor() 函数返回一个可等待的对象,如果需要可以等待。 该任务将立即开始执行,因此不需要等待或安排返回的可等待对象来开始执行阻塞调用。

例如:

...
# 获取事件循环
loop = asyncio.get_running_loop()
# 在单独的线程中执行函数
await loop.run_in_executor(None, task)

或者,可以创建一个执行器并将其传递给loop.run_in_executor()函数,该函数将在执行器中执行异步调用。

在这种情况下,调用者必须管理执行器,在调用者完成后将其关闭。

例如:

...
# 创建一个进程池
with ProcessPoolExecutor as exe:
    # 获取事件循环
    loop = asyncio.get_running_loop()
    # 在单独的线程中执行函数
    # process pool is shutdown automatically...
    # 进程池自动关闭...

这两种方法允许阻塞调用作为 asyncio 程序中的异步任务执行。

The asyncio module provides two approaches for executing blocking calls in asyncio programs.

The first is to use the asyncio.to_thread() function.

This is in the high-level API and is intended for application developers.

The asyncio.to_thread() function takes a function name to execute and any arguments.

The function is executed in a separate thread. It returns a coroutine that can be awaited or scheduled as an independent task.

For example:

...
# execute a function in a separate thread
await asyncio.to_thread(task)

The task will not begin executing until the returned coroutine is given an opportunity to run in the event loop.

The asyncio.to_thread() function creates a ThreadPoolExecutor behind the scenes to execute blocking calls.

As such, the asyncio.to_thread() function is only appropriate for IO-bound tasks.

An alternative approach is to use the loop.run_in_executor() function.

This is in the low-level asyncio API and first requires access to the event loop, such as via the asyncio.get_running_loop() function.

The loop.run_in_executor() function takes an executor and a function to execute.

If None is provided for the executor, then the default executor is used, which is a ThreadPoolExecutor.

The loop.run_in_executor() function returns an awaitable that can be awaited if needed. The task will begin executing immediately, so the returned awaitable does not need to be awaited or scheduled for the blocking call to start executing.

For example:

...
# get the event loop
loop = asyncio.get_running_loop()
# execute a function in a separate thread
await loop.run_in_executor(None, task)

Alternatively, an executor can be created and passed to the loop.run_in_executor() function, which will execute the asynchronous call in the executor.

The caller must manage the executor in this case, shutting it down once the caller is finished with it.

For example:

...
# 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...

These two approaches allow a blocking call to be executed as an asynchronous task in an asyncio program.


最后更新: 2024年9月4日
创建日期: 2024年9月4日