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 程序中执行。

相关文章
|
1月前
|
数据采集 Java Python
python并发编程:Python异步IO实现并发爬虫
python并发编程:Python异步IO实现并发爬虫
24 1
|
1月前
|
算法 数据处理 Python
Python并发编程:解密异步IO与多线程
本文将深入探讨Python中的并发编程技术,重点介绍异步IO和多线程两种常见的并发模型。通过对比它们的特点、适用场景和实现方式,帮助读者更好地理解并发编程的核心概念,并掌握在不同场景下选择合适的并发模型的方法。
|
15天前
|
调度 数据库 Python
【专栏】异步IO在处理IO密集型任务中的高效性
【4月更文挑战第27天】本文介绍了Python并发编程和异步IO,包括并发的基本概念(多线程、多进程、协程),线程与进程的实现(threading和multiprocessing模块),协程的使用(asyncio模块),以及异步IO的原理和优势。强调了异步IO在处理IO密集型任务中的高效性,指出应根据任务类型选择合适的并发技术。
|
5天前
|
API UED Python
使用Python进行异步HTTP请求的实践指南
使用Python进行异步HTTP请求的实践指南
19 4
|
13天前
|
并行计算 数据处理 开发者
Python并发编程:解析异步IO与多线程
本文探讨了Python中的并发编程技术,着重比较了异步IO和多线程两种常见的并发模型。通过详细分析它们的特点、优劣势以及适用场景,帮助读者更好地理解并选择适合自己项目需求的并发编程方式。
|
16天前
|
人工智能 算法 调度
uvloop,一个强大的 Python 异步IO编程库!
uvloop,一个强大的 Python 异步IO编程库!
24 2
|
17天前
|
API 调度 开发者
Python中的并发编程:使用asyncio库实现异步IO
传统的Python编程模式中,使用多线程或多进程实现并发操作可能存在性能瓶颈和复杂性问题。而随着Python 3.5引入的asyncio库,开发者可以利用异步IO来更高效地处理并发任务。本文将介绍如何利用asyncio库实现异步IO,提升Python程序的并发性能。
|
23天前
|
数据采集 缓存 算法
使用Python打造爬虫程序之Python中的并发与异步IO:解锁高效数据处理之道
【4月更文挑战第19天】本文探讨了Python中的并发与异步IO,区分了并发(同时处理任务)与并行(同时执行任务)的概念。Python的多线程受限于GIL,适合IO密集型任务,而多进程适用于CPU密集型任务。异步IO通过非阻塞和回调/协程实现高效IO,Python的asyncio库提供了支持。应用场景包括Web开发和网络爬虫等。实践指南包括理解任务类型、使用asyncio、避免阻塞操作、合理设置并发度和优化性能。理解并运用这些技术能提升Python程序的效率和性能。
|
25天前
|
开发者 Python
Python中的并发编程:使用asyncio模块实现异步任务
传统的Python编程中,使用多线程或多进程进行并发操作时,常常会面临性能瓶颈和资源竞争的问题。而随着Python 3.5版本的引入,asyncio模块为开发者提供了一种基于协程的异步编程方式。本文将介绍如何使用asyncio模块实现异步任务,提高Python程序的并发处理能力。
|
25天前
|
监控 NoSQL 测试技术
python使用Flask,Redis和Celery的异步任务
python使用Flask,Redis和Celery的异步任务