2020/01/19 05-asyncio和aiohttp(面试问协程)

在这里插入图片描述
IO时间比较长,异步一般返回不是最终结果的结果(往往是给一个好牌,好了叫你)
IO有两个阶段。在内核阶段,就绪好,搬到了用户空间阶段。
异步IO是最高效的,asyncio在3.4的时候加入了标准库,基于selectors实现,看似库,其实是个框架。

在这里插入图片描述
为什么要引入异步IO,先看例子
在这里插入图片描述在这里插入图片描述
加个time,就可以出现交替的情况,多线程在这里插入图片描述
真并行是不可预期的
在这里插入图片描述
这个是多进程在这里插入图片描述
多进程,多线程,并行和串行,多进程是真正的并行,多线程是假并行,线程也是并行的解决方案,因为有GIL(进程级别的锁),写python的人需要知道GIL
在这里插入图片描述
在这里插入图片描述
生成器函数必须调用一次
在这里插入图片描述
这个代码就把协程的概念体现出来了
假并行,一旦yield完成,另一个才继续跑,一yield,就让出控制权,有循环保证就交给另一个,这样重复
等于用生成器去进行一种调度
在这里插入图片描述
是在当前线程内,用最简单的方式实现了一种调度,这就是协程最原始的雏形,协程的思想是让生成器遇到yield的时候,会让出控制权,反而可以执行其他代码
在这里插入图片描述在这里插入图片描述
在一个线程内,通过生成器的对象,就完成了调度,这样让两个函数都有机会去执行,每个生成器对象在执行的时候,next会执行一段事件,但是只是执行到下一次yield位置上,不到yield绝对不停,这样的调度不是进程和线程的调度,这样的调度纯粹是在线程内写代码完成的

所以这个代码需要这么写,调度的东西需要有yield,yield的时候需要让出控制权,将程序让给其他的语句来执行,其他语句yield完之后,其他的才有机会,所以需要一个循环帮助交替执行
在这里插入图片描述
asyncio就是用的这个思想在这里插入图片描述
有一个大循环就可以周而复始指定你所指定的次数在这里插入图片描述
有了循环可以stop
在这里插入图片描述
有了循环可以run_forever
在这里插入图片描述
现在派任务,把任务运行完,asyncio是异步,这些任务都需要时间,是不能立即得到结果的,(跟current.future是一样的,要等future对象执行完了,看它是否dump一个道理)
future和task是子类的关系,如果扔一个协程对象,将你的协程对象直接封装成task,也就是放了future的子类对象

在这里插入图片描述
关闭循环
在这里插入图片描述
判断循环是否运行
在这里插入图片描述
直接把一个协程对象创建成一个task在这里插入图片描述
协程可能在面试的时候问你在这里插入图片描述
协程coroutine不是进程也不是线程,是在用户空间调度完成并发处理的一种方式。是一种交替执行,是一种假并发。交替执行,就是在等待IO的时候,跑另一个协程

yield出来的时候正好在做IO访问,比较浪费时间,所以需要把控制权让出来,因为这里需要IO等待数据到来,等待IO的时候让出控制权,可以把时间留给能跑的生成器函数执行
在这里插入图片描述
在用户空间内,没有用到多线程,进程和线程的调度取决于操作系统,刚才的for循环是我们写的,确实是我们来控制的。
面试可能问协程和线程进程的关系,进程和线程是操作系统必须支持的功能,由操作系统来进行调度,协程是我们在代码里写的大循环,由它来控制写的协程对象,谁先执行谁后执行,但是要加大循环在这里插入图片描述
多线程不宜过多,因为线程的切换是比较消耗资源的,所有的切换都需要消耗资源,因为CPU不是给你一个人使用的,每个执行的数据切换的时候需要保存,轮到你下一次执行,恢复数据。
进程频繁切换,消耗很大,所以多线程的开销也很大,避免这样就可以用协程,协程是一种非抢占调度,之所以不能预测多线程的结果,该轮到谁是cpu说了算,是一种争抢式的策略

协程是一种非争抢式的调度,多线程是抢占的,所以结果不容易预测(有个线程可能一直醒着,其他都在睡眠)
在这里插入图片描述next下一个,yield就换,是一种非争抢式的调度在这里插入图片描述
协程也不需要锁机制,在同一个线程执行,不需要加锁,使用协程会避免把处理的东西分布在多个线程中
锁容易带来死锁,加了锁,效率低
用协程的时候避免使用多线程
在这里插入图片描述
多CPU下,可以发挥多进程,因为进程是真的并发,协程可以解决多线程的问题
协程是基于生成器来搞的

在这里插入图片描述
3.4之后专门引入asyncio库
在这里插入图片描述在这里插入图片描述
coroutine协程
在这里插入图片描述
**
首先建立大循环,然后跑任务,跑完close()**在这里插入图片描述在这里插入图片描述
运行的时候会把协程对象转换成task(task是future的子类)对象在这里插入图片描述
试试是否能用其他方式,也就是run_until_complete里面要放future
在这里插入图片描述
官方例子,把一个函数,这个函数里有yield,生成器函数要转换成coroutine协程,需要前面加上@asyncio.coroutine装饰器进行转换,这个生成器对象,就可以封装成task对象
在这里插入图片描述
也可以create创建出来
在这里插入图片描述
pending的意思就是预备着的,还没有开始执行
任务交给run_until_complete这个循环run起来
到2的时候finished,这个任务就跑完了

在这里插入图片描述
看看能否获得这个result
在这里插入图片描述在这里插入图片描述
task是future的子类,也就是task是一个future对象,future对象调用result方法,就拿到1000
在这里插入图片描述
查看asyncio.Task在这里插入图片描述在这里插入图片描述
是future子类,done了的时候callback 在这里插入图片描述
增加一个call_back即可,call_back里面是函数在这里插入图片描述
这个fn加到call_backs里面去在这里插入图片描述
在这里注册了回调,done了之后调用回调在这里插入图片描述
3在2的上面,因为执行完已经done了
在这里插入图片描述
也可以拿到future.result对象在这里插入图片描述
把协程函数添加到大循环,循环之后要不要加回调取决于你,不加回调可以从任务上返回结果,task.result()
整个过程是一个异步过程,循环很多下,才得出最终的结果1000

在这里插入图片描述在这里插入图片描述
这后面的又是一个coroutine,可以暂时理解为生成器对象,生成器对象可以从中yield
yield from相当于从里面单个值yield
在这里插入图片描述
可以这么写
在这里插入图片描述
现在就有两个协程对象
在这里插入图片描述
这里面本来只能放一个,放不了两个协程对象在这里插入图片描述
把这两个协程对象放到集合里,集合里面可以放coroutine对象,或者task对象,future对象
但是现在出现了问题,这个列表不是个coroutie,不认识,列表不是一个awaitiable对象
在这里插入图片描述
这里提供了asyncio.wait()函数,用这个函数把tasks一包即可
在这里插入图片描述
现在如果要拿到这个b的结果,
第一种创建task对象(future对象),这个状态变化可以通过future对象来访问
第二种是run_until_complete,这个函数有一个返回值
在这里插入图片描述在这里插入图片描述
b这里没有return
ret会把执行过的所有任务,封装以后返回,我们遍历一下即可
在这里插入图片描述
把时间调大
在这里插入图片描述
上面不执行完下面就执行不了,是按照顺序执行的
在这里插入图片描述
现在就可以用这个来解决一些问题在这里插入图片描述
首先需要get_event_loop创建一个大循环,然后可以创建tasks,放到里面跑任务在这里插入图片描述
还可以create_task封装成一个task对象在这里插入图片描述
多个任务就需要封装在一起,用wait方法包装
*在这里插入图片描述
这是3.4早期的用法,到了3.5就不推荐这么写了,推荐用原生的关键字写,async def,await,这就是语法上原生支持了异步的
在这里插入图片描述
用这样的方式也可以跑起来在这里插入图片描述
await是一条语句,是keyword
在这里插入图片描述
有特殊的方法在这里插入图片描述
也就是从此之后,await后面不能随便放这个东西,要么是一个coroutine,可迭代对象需要包装成一个corroutine,或者这个可迭代对象必须__await__方法,有了这个方法才能算一个awaitable对象
在这里插入图片描述3.5版本开始,python提供关键字async,await,在语言上原生支持协程
在这里插入图片描述在这里插入图片描述
aysnc def是用来定义协程的,iscoroutinefunction()判断一个协程函数是否可以运行。协程函数中可以不包含await、
async关键字,但不能使用yield关键字
在这里插入图片描述
协程函数调用会返回一个协程对象,协程对象用iscoroutine()来判断在这里插入图片描述
**await语句之后是awaitable对象,可以是协程或者实现了__await__()方法的对象,await会暂停当前协程执行,让出控制权,让loop调度其他协程。 **
在这里插入图片描述在这里插入图片描述
wait会判断现在是不是coroutine,是coroutine会包装成一个task
在这里插入图片描述
注意:需要有协程,需要有大循环

看一个例子TCP Echo Server

在这里插入图片描述在这里插入图片描述在这里插入图片描述
首先需要一个大循环,有IP地址和端口,就需要有一个handle(如何处理数据)
在这里插入图片描述
这个会创建一个监听在一个端口上一个server对象出来
在这里插入图片描述
有了这个对象可以让下面的循环跑起来,有了请求需要有内部机制调用handle函数
在这里插入图片描述
要知道读写对象才能操作socket,有个请求来就会调用handle,会帮你注入两个参数,
在这里插入图片描述有个请求来就会调用handle,会帮你注入两个参数,read(StreamReader)和write(StreamWriter),请求来了之后可以read读取内容,也可以write写数据进去在这里插入图片描述

查看后面等什么
在这里插入图片描述
是一个coroutine,awaitable对象在这里插入图片描述
drain台风,这里不用flush,是因为没有提供flush,点进去在这里插入图片描述
这个就是flush在这里插入图片描述
运行一下
在这里插入图片描述
链接发送消息
在这里插入图片描述在这里插入图片描述
pername可以拿到对端地址在这里插入图片描述
这就是怎么去用异步server

aiohttp 可以快速搭建网站

异步库里有aiohttp库
在这里插入图片描述在这里插入图片描述
都是在一个线程进行调度,大循环的

web.Application()建立一个web应用程序,
router.add_get配置路由,解决get方法的跟/的访问,indexhanle首页怎么处理
**
在这里插入图片描述
访问这个域名会调用indexhandle函数在这里插入图片描述
如果后面放Id就会调用hanle
在这里插入图片描述
self.requqst客户端链接过来的都叫请求在这里插入图片描述
最后告诉在什么地址端口跑
在这里插入图片描述在这里插入图片描述在这里插入图片描述
大循环
在这里插入图片描述
调用url,把url传进来在这里插入图片描述
传进去后建立一个session,状态码和内容在这里插入图片描述在这里插入图片描述
** https://aiohttp.readthedocs.io/en/stable/这里就是帮助

在这里插入图片描述
快速搭建网站可以使用,异步IO效果不错在这里插入图片描述
可以在每个handle上加一个装饰器,告诉装饰器从哪里路由在这里插入图片描述
每一个路径应该对应一个处理方法
在这里插入图片描述
地址的变动可以映射到函数上去,这个叫路由
在这里插入图片描述
首先启动一个应用,注册路由和对这些函数的对应关系
在这里插入图片描述
告诉在哪个端口上
在这里插入图片描述
启动服务
在这里插入图片描述
返回一个1在这里插入图片描述
查看handle函数,有匹配信息
在这里插入图片描述在这里插入图片描述
发送 的这个数据匹配的是1,1 是定义为上面的ID的,没有拿到1就返回0000
在这里插入图片描述
如果是/根访问的就是indexhandle在这里插入图片描述
返回的就是path
在这里插入图片描述
还有一种批量的,add_routes增加一批routes,给一个列表,列表里就是写路径和函数的对应关系
在这里插入图片描述
服务端增加点东西
在这里插入图片描述

查看下客户端

在这里插入图片描述
启动一下,就拿到了
在这里插入图片描述
2就是传过去的url
在这里插入图片描述
这个命令行一样的客户端访问了启动的web服务器,交互了一次,拿到了response
在这里插入图片描述
通过get方法向这个url发起一个请求,返回响应码,和url内容
在这里插入图片描述
异步库就需要查看官方代码,拿过来抄一下在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值