type
status
date
slug
summary
tags
category
icon
password
事件循环
理解成一个死循环,去检测去执行某些代码
伪代码
快速上手
协程函数:
async def
函数名协程对象:协程函数+(),执行协程函数,得到的就是协程对象
注意:执行协程函数创建协程对象,函数内部代码并不会被执行,要执行函数必须和事件循环搭配起来使用
await
await+可等待的对象(协程对象,future对象,Task对象 都可以理解成====⇒ io等待)
案例1
案例2
案例3
await
关键字在等待对应的值返回结果后再继续执行后续代码。不过,你可能会觉得,这听起来像是同步执行——即一个任务执行完后再执行下一个任务。实际上,情况并非如此。当代码遇到 await
时,它会暂停当前的 async
函数的执行,等待结果返回,但在此期间,Python 解释器可以继续执行其他的 async
函数,从而实现异步操作。
执行协程函数的顺序由什么决定?
在 Python 中,
await
的工作原理涉及到事件循环(Event Loop)的调度机制。事件循环负责调度和执行多个协程(coroutines),使得这些协程可以并发地运行。它的核心思想是,当一个协程遇到 await
时,它会将控制权返回给事件循环,事件循环可以选择运行其他处于就绪状态的协程。我来举个简单的例子,帮助你理解这个过程。
解释:
- 任务启动:在
main()
函数中,我们通过asyncio.gather()
同时启动了task1()
和task2()
这两个异步任务。
- 任务执行:
task1()
开始执行并打印 "Task 1: Started"。task2()
开始执行并打印 "Task 2: Started"。
await
暂停:task1()
遇到await asyncio.sleep(2)
时,会暂停执行,等待 2 秒。- 事件循环立即切换去执行
task2()
,因为task2()
只需要等待 1 秒钟,因此task2()
会先完成。
- 任务完成:
task2()
先打印 "Task 2: Finished after 1 second",并结束。- 在
task2()
结束后,事件循环返回执行task1()
,2 秒等待时间结束后,task1()
打印 "Task 1: Finished after 2 seconds"。
总结:
- 事件循环根据哪个任务的
await
状态来决定执行哪个async
函数。在await
过程中,事件循环会去执行其他就绪的协程。
- 这个例子中,
task2()
先完成,因为它的await
时间较短。事件循环让task2()
完成后,再回到task1()
完成它的等待操作。
希望这个例子帮助你更好地理解
async
和 await
的执行机制!Task对象
在事件循环中添加多个任务
Tasks用于并发调度协程,通过asyncio.create_task(协程对象)的方式创建Task对象,这样可以让协程加入事件循环中等待被调度执行。除了使用 asyncio.create_task()函数以外,还可以用低层级的1oop.create_task()或 ensure_future()函数。不建议手动实例化 Task 对象。
示例1
示例2
在 Python 的
asyncio
模块中,asyncio.create_task()
、asyncio.wait()
和 asyncio.run()
是常用的函数,它们各自有特定的用途和使用场景。下面是对它们的解释以及它们接收的参数类型:1. asyncio.create_task()
- 作用: 这个函数用于创建一个新的任务(即协程对象的调度执行)。它将一个协程包裹成一个任务,并提交给事件循环处理。任务会立即启动并异步执行。
- 参数:
- 接收一个协程对象(coroutine)作为参数,例如
func()
。
- 返回值: 返回一个
Task
对象,表示正在进行的异步操作。
- 示例:
2. asyncio.wait()
- 作用: 这个函数用于等待一个或多个协程(或任务)完成。可以选择等待所有任务完成,或者当其中任意一个任务完成时就返回。
- 参数:
- 接收一个可迭代的协程或任务(例如
task_list
)作为参数。 - 可选参数
timeout
可以指定等待的超时时间。 - 可选参数
return_when
可以指定何时返回(如asyncio.ALL_COMPLETED
或asyncio.FIRST_COMPLETED
)。
- 返回值: 返回一个包含两个集合的元组
(done, pending)
,done
包含已经完成的任务,pending
包含尚未完成的任务。
- 示例:
3. asyncio.run()
- 作用: 这个函数用于运行整个异步程序。它接收一个协程对象,将其运行直至完成,适用于在顶层启动异步代码。
- 参数:
- 接收一个协程对象(coroutine),通常是
async
函数的调用(例如main()
)。
- 返回值: 返回协程运行完成后的结果。
- 示例:
总结
asyncio.create_task()
:用于启动一个协程并让它异步执行,适用于并发执行多个任务的情况。
asyncio.wait()
:用于等待多个任务的完成,可以指定等待所有任务完成或只等待第一个完成。
asyncio.run()
:用于启动并运行整个异步程序,适用于主程序的入口。
这些函数可以组合使用,实现复杂的异步任务调度和并发控制。
asynic.future对象
Future
对象概述
在 Python 的
asyncio
模块中,Future
对象代表一个异步操作的最终结果。它类似于 JavaScript 中的 Promise
。一个 Future
对象并不执行任何实际的计算,它只是一个容器,用于存储异步操作的最终结果或异常。- 未完成状态: 当一个
Future
对象被创建时,它通常处于“未完成”状态,这意味着结果还不可用。
- 完成状态: 当异步操作完成后,
Future
对象的状态会变为“完成”,此时可以从Future
对象中获取结果。
Future
对象通常不需要直接创建,因为高层次的 asyncio
API 会自动处理它们。但理解 Future
是如何工作的,对于深入掌握 Python 的异步编程模型非常重要。Future
对象的使用场景
Future
对象在以下场景中很有用:- 协程与回调之间的桥梁: 你可以使用
Future
对象将一个异步操作的结果传递给一个回调函数。
- 手动管理异步任务的结果: 在某些高级用例中,你可能希望手动创建和操作
Future
对象。
举个简单的例子
以下是一个使用
Future
对象的简单例子。这个例子模拟了一个异步操作,该操作在完成后手动设置 Future
对象的结果:代码解析
- 创建
Future
对象:
在这个例子中,我们通过事件循环创建了一个
Future
对象。此时,future
处于“未完成”状态。- 异步设置
Future
对象的结果:
我们启动了一个异步任务
set_future_value(future)
,它将在 2 秒后通过 future.set_result('操作完成!')
来设置 Future
对象的结果。- 等待
Future
对象的结果:
在
main()
函数中,我们使用 await
来等待 Future
对象的结果。当结果被设置后,await future
语句会继续执行,result
变量将会接收到 future
的结果。- 最终输出:
当
Future
对象完成后,结果会被打印出来。总结
Future
对象代表了一个尚未完成的异步操作的结果。
- 你可以通过
set_result()
方法手动设置Future
对象的结果。
- 使用
await future
可以等待Future
对象完成并获取其结果。
通过这个简单的例子,你可以看到如何使用
Future
对象来管理和获取异步操作的结果。在实际应用中,很多时候你不需要直接使用 Future
对象,因为 asyncio
提供的高层 API 已经封装了这些逻辑。concurrent的Future对象
concurrent.futures
是 Python 标准库中的一个模块,它提供了一些工具来执行并发任务。这个模块中也有一个 Future
对象,它的作用和 asyncio.Future
类似,但用于线程池或进程池的并发任务管理。concurrent.futures.Future
的作用
- 状态管理:
Future
对象用于管理异步或并发任务的执行状态和结果。
- 任务完成通知:
Future
对象可以让你查询任务是否完成,并在任务完成后获取结果或捕获异常。
- 回调机制: 你可以向
Future
对象添加回调函数,当任务完成时,回调函数会被调用。
Future
的状态
- 未完成状态: 当一个任务被提交给线程池或进程池时,
Future
对象处于“未完成”状态。
- 完成状态: 当任务完成时,无论是成功还是失败,
Future
对象的状态都会变为“完成”。
举个简单的例子
下面是一个使用
concurrent.futures
模块的 ThreadPoolExecutor
和 Future
对象的简单例子。我们将在线程池中提交一个任务,并使用 Future
对象来获取任务的结果。代码解析
- 任务函数
task
:
这是一个模拟的任务函数,它接收一个秒数作为参数,等待指定的秒数,然后返回一个完成消息。
- 创建线程池执行器:
这里我们使用
ThreadPoolExecutor
创建一个线程池执行器。ThreadPoolExecutor
可以管理和调度多个线程并行执行任务。- 提交任务并获取
Future
对象:
我们将任务
task
提交给线程池,任务会在后台执行。submit
方法返回一个 Future
对象,该对象代表任务的执行结果或状态。- 执行其他操作:
任务在后台运行时,主线程可以继续执行其他操作。这展示了并发执行的优势。
- 等待任务完成并获取结果:
通过调用
future.result()
,我们可以阻塞并等待任务完成。一旦任务完成,这个方法将返回任务的结果。如果任务抛出了异常,这个方法会重新抛出该异常。总结
concurrent.futures.Future
对象用于管理线程池或进程池中的并发任务。
- 你可以通过
executor.submit()
提交任务,并获取一个Future
对象。
- 通过
future.result()
,你可以等待任务完成,并获取结果。
这个例子展示了如何使用
concurrent.futures.Future
对象来执行和管理并发任务,同时也展示了线程池执行器的基本使用方式。异步和非异步模块混合案例
案例:使用asynicio去结合使用不支持异步的模块
效果一摸一样的,但是耗费的资源更多
打赏
如果您觉得我的内容对你有所帮助,不要吝啬你的一键三连!如果你有能力的话也可以通过下面请我喝杯咖啡~金额您随意~如果对文章内容有任何疑问,欢迎加入群组联系我~
- 作者:Don Mark
- 链接:null/article/92fbfaae-99a7-4a1b-ac33-c5f6f21f497e
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。