Python Asyncio总结

Asyncio总结及示例

相关概念

Future类:

此类 是保存 协程 执行的结果类

重要属性及方法如下:
_result:

存放协程返回的结果

_state:

数据结构为:str

存放协程当前的状态; 如下3种状态:_PENDING(等待执行),_FINISHED(执行结束),_CANCELLED(取消执行)

_callbacks:

数据结构为:list

存放协程在执行结束后 需要执行的回调函数们;

result方法

从 _result中获取结果,并返回在这里插入图片描述

add_done_callback方法

添加协程的回调函数,可以添加多个回调函数;如果 协程当前状态(_state)不是_PENDING,就直接添加到事件循环的_ready中; 否则就添加到 _callbacks中;
在这里插入图片描述

set_result方法

标记此协程已经运行完成,并将协程执行结果赋值给 _result;然后将_callbacks中的回调函数们依次放入到事件循环的_ready中;
在这里插入图片描述

Task(Future)类:

此类继承自Future类

重要属性如下:
_loop

此属性存的是 事件循环 对象

_coro

此属性存的是 对应的协程对象

__step

此私有方法 通过调用协程的
result = coro.send(None)
促使协程继续向下执行(类似生成器的send方法); 如果返回的result仍是一个Future类的对象,则继续将此__step放到事件循环中,等待下次执行;否则此协程的结果就是result的值;

Handle类:

此类主要作用为 将函数封装成handle,然后放到事件循环的_ready中;

TimerHandle(Handle)类:

此类继承自Handle类,是个定时执行的handle,比如await asyncio.sleep(1)就是执行的这个handle,然后将此handle放到事件循环的_scheduled中; 等时间到了之后再执行;

BaseEventLoop类(事件循环的类):

这个类 或者说 事件循环 概念是 整个Asyncio异步框架中最重要的部分, 负责handle的存储,定时handle的存储,handle的运行等等

重要属性如下:
_ready:

此数据结构 主要存放 准备好要执行handle对象们;

数据结构 是一个collections.deque 双链表double-ended queue,

至于为什么用 此数据结构,而不 直接使用 list结构,由于此属性的数据操作顺序必须是FIFO,应该是看中此数据结构的 popleft(从左侧弹出一个数据) 时间负责度为O(1),而list为O(n)

_scheduled:

此数据结构 主要存放 定时执行的handle对象们;比如 asyncio.sleep()方法 生成的handle就是放在此数据结构中;等时间到了之后 就会将此数据结构中的handle转移到_ready中;

数据结构是 list,但是其元素排序方式 是按照堆 heapq 的结构排序的;

至于为什么用 堆的方式排序,而不 直接使用 list默认的排序方式,由于此属性 涉及到 弹出最小值(heapq.heappush) 时效率比 min方法更有效率;

_debug:

是否开启debug模式

开启后,如果handle执行时间 超过一定时间(默认0.1s),会打印warning级别的日志 告诉开发人员 可能有些地方 有编写阻塞代码;

call_soon方法

将回调函数 转换为一个handle对象,然后存到_ready中;
在这里插入图片描述

run_forever方法

一直while循环运行(主要运行_ready中的handle)直到调用stop为止;代码如下
在这里插入图片描述

run_until_complete方法

运行_ready中的handle,直到_ready中没有handle,Future完成为止;其实内部调用了run_forever方法
在这里插入图片描述

_run_once方法

每次while循环主要运行的代码部分;也是整个事件循环的主要代码部分; 主要步骤为:

将 底层(系统内核) 已经准备好的socket(各种IO操作(如http请求,mysql数据请求等等)对应的socket,在底层 epoll,select,kqueue等 各种IO多路复用方法给出的结果) 对应的handle放到_ready中;

将_scheduled中的 已经 小于当前时间的定时handle放到_ready中;

对_ready中的handle按照FIFO顺序 依次执行,执行handle过程中,如果遇到新的协程,则会把对应的协程封装成handle放到_ready或者_scheduled中,然后让出cpu, 让后续的handle继续执行,直到_
ready中的所有handle执行完,然后进行下一个while循环;

代码如下

在这里插入图片描述

总结

  • 何为协程:通过yield关键字 实现2(多)个函数交替执行(一个函数执行到某个地方阻塞了,换另一个函数执行)的方法 就是协程;协程是函数级别的并发;
  • 要想实现真正的并发,需要借助Asyncio包,其内置了事件循环等机制,实现了真正意义的协程;
  • python的Asyncio包通过生成器(yield/yield from关键字)实现了协程的并发执行;因此在协程催动执行的过程中,需要用到生成器的send,throw等方法;
  • Asyncio内置的事件循环可以用第三方的实现;比如 基于libuv用Cython写的uvloop,可以让Asyncio更快;
  • epoll和Asyncio的关系:linux的IO多路复用方法如select/epoll等只是事件循环在检测各种底层socket(http请求等)准备好后放到_ready队列中,供事件循环继续处理;
    事件循环只是调用了linux底层提供的多路复用方法而已(事件循环将准备好的socket放到_ready中这个操作 相对于linux底层的IO多路复用 来说就是业务层代码), 选择更高效的socket处理方法(如epoll)让Asyncio更快;
import asyncio
import uvloop

asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())

python异步编程asyncio原理分析

Python并发编程之初识异步IO框架

python协程的原理

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值