并发编程补充
1|0并发编程补充
2|0一、asyncio 模块
asyncio
是Python 3.4版本引入的标准库,用于实现异步编程。它基于事件循环(Event Loop)模型,通过协程(Coroutines)来实现任务的切换和调度(也叫协程模块)。在asyncio
中,我们可以使用async
关键字定义协程函数,并使用await
关键字挂起协程的执行- 异步编程的核心思想是避免阻塞,即当一个任务在等待某个操作完成时,可以让出CPU执行权,让其他任务继续执行。这样可以充分利用CPU的时间片,提高程序的整体效率
- 一旦决定使用异步,则系统每一层都必须是异步,“开弓没有回头箭”
2|11. asyncio中的几个重要概念
-
事件循环
- 事件循环是异步编程的核心机制,它负责协调和调度协程的执行,以及处理IO操作和定时器等事件。它会循环监听事件的发生,并根据事件的类型选择适当的协程进行调度
- 在
asyncio
库中,可以通过asyncio.get_event_loop()
方法获取默认的事件循环对象,也可以使用asyncio.new_event_loop()
方法创建新的事件循环对象
-
Future
- future表示还没有完成的工作结果。事件循环可以通过监视一个future对象的状态来指示它已经完成。future对象有几个状态:Pending、Running、Done、Cancelled
- 创建future的时候,task为pending,事件循环调用执行的时候当然就是running,调用完毕自然就是done,如果需要停止事件循环,就需要先把task取消,状态为cancel
-
Task
-
task是Future的一个子类,它知道如何包装和管理一个协程的执行。任务所需的资源
可用时,事件循环会调度任务,并生成一个结果,从而可以由其他协程消费
-
asyncio.Task
用于实现协作式多任务的库,且Task对象不能用户手动实例化,通过下面2个函数创建:asyncio.async() 、loop.create_task() 或 asyncio.ensure_future()
-
-
coroutine
- 协程对象,指一个使用async关键字定义的函数,它的调用不会立即执行函数,而是会返回一个协程对象。协程对象需要注册到事件循环,由事件循环调用
2|22. asyncio模块的常用方法
(1)run_until_complete()
- 阻塞调用,直到协程运行结束才返回。参数是future、协程对象,传入协程对象时内部会自动变为future
- 在最早的Python 3.4中,协程函数是通过
@asyncio.coroutine 和 yeild from
实现的
(2)asyncio.run()
- 这是异步程序的主入口,相当于C语言中的main函数。此函数总是会创建一个新的事件循环并在结束时关闭之。它应当被用作 asyncio 程序的主入口点,理想情况下应当只被调用一次
- Python 3.7之前执行协程任务都是分三步进行的,代码有点冗余。Python 3.7提供了一个更简便的
asyncio.run
方法,下面代码为asyncio.run
出现前后的对比:
(3)asyncio.sleep()
- 模拟IO操作,这样的休眠不会阻塞事件循环,前面加上await后会把控制权交给主事件循环,在休眠(IO操作)结束后恢复这个协程
- 注意:若在协程中需要有延时操作,应该使用
await asyncio.sleep()
,而不是使用time.sleep()
,因为使用time.sleep()
后会释放GIL,阻塞整个主线程,从而阻塞整个事件循环
(4)async 和 await
- python在3.5以后引入
async
和await
,代替了asyncio.coroutine
装饰器,基于他编写的协程代码其实就是上一示例的加强版,让代码可以更加简便可读 async
用在定义函数之前,声明当前定义的函数时一个异步函数- 异步函数不能直接调用,直接调用异步函数不会返回结果,而是返回一个coroutine对象。需要放在异步框架中调用
await
的作用是挂起一个函数,在挂起时,该挂起函数仍在执行,而当前线程会去执行其他异步函数,而不是阻塞住等其全部执行完;当挂起函数执行完成后,线程会从其它异步函数返回继续执行挂起函数之后的内容await
只可对异步函数使用(本质是实现了 __await__ 方法的类
),且只能在一个异步函数中使用
(5)asyncio.create_task()
-
asyncio.create_task()
其是对loop.create_task()
的封装,相当于创建并行的任务 -
接收一个协程,返回一个
asyncio.Task
的实例,也是asyncio.Future
的实例,毕竟Task是Future的子类。返回值可直接传入run_until_complete()
-
返回的Task对象可以看到协程的运行情况
-
我们只执行了单个协程任务(函数)。实际应用中,我们先由协程函数创建协程任务,然后把它们加入协程任务列表,最后一起交由事件循环执行。
根据协程函数创建协程任务有多种方法,其中最新的是Python 3.7版本提供的
asyncio.create_task
方法,如下所示:
- 简单实例
(6)asyncio.wait() 和 asyncio.gather()
-
wait()
方法将task任务列表加入到当前的事件循环中,等待多个异步任务完成等;(注意:必须先创建事件循环,后加入任务列表,否则会报错) -
asyncio.wait()
是一个协程,不会阻塞,立即返回,返回的是协程对象。传入的参数是future或协程构成的可迭代对象。最后将返回值传给run_until_complete()加入事件循环 -
相同
- 从功能上看,
asyncio.wait
和asyncio.gather
实现的效果是相同的,都是把所有 Task 任务结果收集起来
- 从功能上看,
-
不同:
-
asyncio.wait
使用一个set保存它创建的Task实例,因为set是无序的所以这也就是我们的任务不是顺序执行的原因。会返回两个值:done 和 pending,done 为已完成的协程 Task,pending 为超时未完成的协程 Task,需通过 future.result 调用 Task 的 result;而
asyncio.gather
返回的是所有已完成 Task 的 result,不需要再进行调用或其他操作,就可以得到全部结果,如果列表中传入的不是create_task方法创建的协程任务,它会自动将函数封装成协程任务
-
i. asyncio.wait实例
- 最常见的写法是:
await asyncio.wait(task_list)
ii. asyncio.gather 实例
- *注意
await asyncio.gather(*task_list)
,注意这里 task_list 前面有一个 (把list解构)
(7)add_done_callback回调
- 我们还可以给每个协程任务通过add_done_callback的方法给单个协程任务添加回调函数
(8)其他
2|33. 简单的协程实例
- 基于python3.5及之后版本
__EOF__

本文链接:https://www.cnblogs.com/Mcoming/p/17674668.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2020-09-03 前端-排坑
2020-09-03 后端-排坑