Python 异步: 常见问题 Part_2(23)

简介: Python 异步: 常见问题 Part_2(23)

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

本节回答开发人员在 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种方式来发布后续任务:

  1. 从已完成的任务本身安排后续任务。
  2. 安排呼叫者的后续任务。
  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 程序中执行。

相关文章
|
27天前
|
数据采集 JSON 测试技术
Grequests,非常 Nice 的 Python 异步 HTTP 请求神器
在Python开发中,处理HTTP请求至关重要。`grequests`库基于`requests`,支持异步请求,通过`gevent`实现并发,提高性能。本文介绍了`grequests`的安装、基本与高级功能,如GET/POST请求、并发控制等,并探讨其在实际项目中的应用。
37 3
|
2月前
|
关系型数据库 MySQL 数据处理
探索Python中的异步编程:从asyncio到异步数据库操作
在这个快节奏的技术世界里,效率和性能是关键。本文将带你深入Python的异步编程世界,从基础的asyncio库开始,逐步探索到异步数据库操作的高级应用。我们将一起揭开异步编程的神秘面纱,探索它如何帮助我们提升应用程序的性能和响应速度。
|
2月前
|
调度 Python
深入理解 Python 中的异步操作 | python小知识
在现代编程中,异步操作是一个非常重要的概念,尤其是在处理 I/O 密集型任务时。使用异步操作可以显著提高程序的性能和响应速度。Python 提供了 `async` 和 `await` 关键字,使得编写异步代码变得更加直观和简洁【10月更文挑战第8天】
37 2
|
2月前
|
数据采集 前端开发 NoSQL
Python编程异步爬虫实战案例
Python编程异步爬虫实战案例
81 2
|
1月前
|
NoSQL 关系型数据库 MySQL
python协程+异步总结!
本文介绍了Python中的协程、asyncio模块以及异步编程的相关知识。首先解释了协程的概念和实现方法,包括greenlet、yield关键字、asyncio装饰器和async/await关键字。接着详细讲解了协程的意义和应用场景,如提高IO密集型任务的性能。文章还介绍了事件循环、Task对象、Future对象等核心概念,并提供了多个实战案例,包括异步Redis、MySQL操作、FastAPI框架和异步爬虫。最后提到了uvloop作为asyncio的高性能替代方案。通过这些内容,读者可以全面了解和掌握Python中的异步编程技术。
51 0
|
2月前
|
数据处理 Python
深入探索:Python中的并发编程新纪元——协程与异步函数解析
深入探索:Python中的并发编程新纪元——协程与异步函数解析
31 3
|
2月前
|
网络协议 安全 Java
难懂,误点!将多线程技术应用于Python的异步事件循环
难懂,误点!将多线程技术应用于Python的异步事件循环
97 0
|
2月前
|
数据采集 JSON 网络协议
Python编程异步爬虫——aiohttp的使用
Python编程异步爬虫——aiohttp的使用
59 0
|
2月前
|
数据采集 调度 Python
Python编程异步爬虫——协程的基本原理(一)
Python编程异步爬虫——协程的基本原理(一)
24 0
|
2月前
|
数据采集 Python
Python编程异步爬虫——协程的基本原理(二)
Python编程异步爬虫——协程的基本原理(二)
26 0