最全Python异步IO实现全过程_实现异步io(1),美团Python研发岗二面

做了那么多年开发,自学了很多门编程语言,我很明白学习资源对于学一门新语言的重要性,这些年也收藏了不少的Python干货,对我来说这些东西确实已经用不到了,但对于准备自学Python的人来说,或许它就是一个宝藏,可以给你省去很多的时间和精力。

别在网上瞎学了,我最近也做了一些资源的更新,只要你是我的粉丝,这期福利你都可拿走。

我先来介绍一下这些东西怎么用,文末抱走。


(1)Python所有方向的学习路线(新版)

这是我花了几天的时间去把Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

最近我才对这些路线做了一下新的更新,知识体系更全面了。

在这里插入图片描述

(2)Python学习视频

包含了Python入门、爬虫、数据分析和web开发的学习视频,总共100多个,虽然没有那么全面,但是对于入门来说是没问题的,学完这些之后,你可以按照我上面的学习路线去网上找其他的知识资源进行进阶。

在这里插入图片描述

(3)100多个练手项目

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了,只是里面的项目比较多,水平也是参差不齐,大家可以挑自己能做的项目去练练。

在这里插入图片描述

(4)200多本电子书

这些年我也收藏了很多电子书,大概200多本,有时候带实体书不方便的话,我就会去打开电子书看看,书籍可不一定比视频教程差,尤其是权威的技术书籍。

基本上主流的和经典的都有,这里我就不放图了,版权问题,个人看看是没有问题的。

(5)Python知识点汇总

知识点汇总有点像学习路线,但与学习路线不同的点就在于,知识点汇总更为细致,里面包含了对具体知识点的简单说明,而我们的学习路线则更为抽象和简单,只是为了方便大家只是某个领域你应该学习哪些技术栈。

在这里插入图片描述

(6)其他资料

还有其他的一些东西,比如说我自己出的Python入门图文类教程,没有电脑的时候用手机也可以学习知识,学会了理论之后再去敲代码实践验证,还有Python中文版的库资料、MySQL和HTML标签大全等等,这些都是可以送给粉丝们的东西。

在这里插入图片描述

这些都不是什么非常值钱的东西,但对于没有资源或者资源不是很好的学习者来说确实很不错,你要是用得到的话都可以直接抱走,关注过我的人都知道,这些都是可以拿到的。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

async 包与 async/await 关键字

现在你已经有了一定的异步IO的背景知识,现在来看看Python内的实现。Python的 asyncio 包(从Python 3.4开始引入)和 async、await 两个关键字虽然用于不同的目的,但是他们共同实现了声明、构建、执行以及管理异步代码的功能。

async/swait句法以及原生协程

警告:警惕你在网上读到的内容,Python的async IO已经从Python 3.4迅速发展到Python 3.7了。很多就旧的模式都被废弃了,而一些原先被禁止的也在新版本中开始使用。就我所知,本教程也很快就会过时。

异步IO的核心是协程,协程是Python生成器方法的一个特定版本。我们先从基础定义开始,然后再进行构建:协程是一个可以在自身结束之前挂起的方法,并且它可以将控制器传给其它协程一段时间。

之后,你将深入了解到传统生成器是如何作用于协程的。现在,了解协程的最简单方法是实现一个协程。

现在我们采取一种直观的方式编写一些异步IO代码。这虽然是一个很简短的实现了异步IO的 Hello World 方法,但是对了解其核心功能很有帮助。

运行这个文件的时候,注意它与仅仅使用 def 和 time.sleep() 的定义有什么不同:

这个输出的顺序是异步IO的核心,由单一事件循环或协调器负责与每一个 count() 方法调用交流。当每一个任务执行到 await asyncio.sleep(1))时,函数会通知事件循环并交出控制权限,“我要睡眠一秒钟,在此期间,继续做其他有意义的事”。

与同步版本对比:

执行后,在输出顺序和时间上有一些轻微但很重要的变化

使用 time.sleep() 和 asyncio.sleep() 看起来有点简陋,这里一般用来替代标准输入等耗时的操作。(最简单的等待就是使用 sleep(),基本上什么也不做。)也就是说 time.sleep() 可以表示任何耗时的阻塞函数的调用,而 asyncio.sleep() 用于表示非阻塞的函数调用(但是也是需要一定时间来完成)。

在下一节你将看到,等待(包括 syncio.sleep())的好处是可以让正在执行的函数暂时将控制权限交给另一个可以立即执行某些操作的函数。相对的,time.sleep() 或者其他阻塞调用不可用于异步的Python代码,因为它将在等待时间内暂停进程内的全部操作。

Async IO的规则

至此,async,await 和协程创建的规则有一种更为正式的定义。本节的内容有一些繁重,但是有助于了解 async/await。如有必要,可以先回顾以下内容:

* 句法 async def引入了原生协程或者说异步生成器。表达式async with 和 async for 也是允许的,稍后就可以看到。

* 关键字 await 将控制器传递给时间循环。(挂起当前运行的协程。)Python执行的时候,在  g() 函数范围内如果遇到表达式 await f(),就是 await 在告诉事件循环“挂起 g() 函数,直到 f() 返回结果,在此期间,可以运行其他函数。”

上述第二点在代码中大致如下:

关于要不要用 async/await,以及何时使用,如何使用,都有一套严格的规则。无论你是在使用语法还是已经使用 async/await,这些规则都会很方便:

1. 协程是引入了async def的函数。你可能会用到await,return或者yield,但是这些都是可选的。Python允许使用async def noop(): pass声明:

1.1. 使用 await 与 return 的组合创建协程函数。想要调用一个协程函数,必须使用 await 等待返回结果。

1.2. 在 async def 代码块中使用 yield 的情况并不多见(只有Python的近期版本才可用)。当你使用 async for 进行迭代的时候,会创建一个异步生成器。暂时先忘掉异步生成器,将目光放在使用 await 与 return 的组合创建协程函数的语法上。

1.3. 在任何使用 async def 定义的地方都不可以使用 yield from,这会引发异常 SyntaxError。

2.一如在****def定义的函数之外使用yield会引发异常SyntaxError,在async def定义的协程之外使用await也会引发异常SyntaxError。你只能在协程内部使用await。

这里有一个简介的例子,总结了上面的几条规则:

最后,当你使用 await f() 时,要求 f() 是一个可等待的对象。但这并没有什么用。现在,只需要知道可等待对象要么是(1)其他的协程,要么就是(2)定义了 .await()函数且返回迭代器的对象。如果你正在编写程序,绝大多数情况只需要关注案例#1。

这给我们带来了一些技术上的差异:将一个函数标记为协程的旧的一个方式是使用 @asyncio.coroutine装饰一个普通的函数。这是基于生成器的协程。但是这种方式自Python 3.5中出现了async/await 语法后就已经过时了。

下面两个协程基本上是等价的(都是可等待的),但第一个是基于生成器的,而第二个是原生协程。

如果你写代码的时候更趋向于显式声明而不是隐式声明,那么最好是使用原生协程。基于生成器的协程将会在Python 3.10版本移除。

本教程的后半部分,我们会再涉及一些基于生成器的协程的优点。为了使协程成为Python中独立的标准功能,并与常规生成器区分开,以减少歧义,Python引入 async/await。

不要沉迷于基于生成器的协程,它已经被 async/await 取代了。如果你要使用 async/await 语法的话,注意它的一些特有的规则(比如,await 不能用于基于生成器的协程),这些规则很大程度上与基于生成器的协程不兼容

闲话少说,现在来看几个更复杂点的例子。

这是一个介绍异步IO如何减少等待时间的例子:给定一个协程 makerandom(),它在 0-10 之间产生一个随机整数,直到有一个数超出阈值为止。现在想多次调用这个协程而不必等待每一次调用结束,可以参照上面的两个脚本的模式,只需稍作修改:

对于上面脚本的运行方式,彩色输出要比我说的描述的更清楚。

rand.py execution

这个程序通过 3 个不同的输入来运行同一个协程 makerandom。大多数程序包含小的模块化的协程和一个用于将每一个小协程链接到一起的包装函数。这里 main() 函数通过将主协程映射到某些迭代或池来聚集多个 task(features)。

在这个小例子中,池是 range(3)。稍后更完整的示例中,池变成了一组需要请求,解析和处理的URL,而 main()则是为每一个URL封装了一个协程。

尽管“生成随机整数”(主要是计算密集型任务)可能不是展示 asyncio 的首选,但是在示例中的 asyncio.sleep()目的是模仿一个等待时间不确定的I/O密集型任务。比如,调用 asyncio.sleep() 可以表示在消息应用中客户端与服务端之间收发消息的非整数随机时间。

Async IO设计模式

本节将向你介绍一些异步IO自带的可行的脚本设计。

链接协程

协程的一个关键特性是它们可以被链接到一起。(记住,一个协程是可等待的,所以另一个协程可以使用 await 来等待它。)这个特性允许你将程序划分成更小的,可管理可回收的协程:

注意观察输出,part1() 的睡眠时间是可变的,而当它的返回结果可用的时候,part2() 开始执行并使用这些结果。

按照设定,main()函数执行的时间应该与它聚集在一起的任务中最长的一个执行时间相同。

使用队列

在 asyncio 包中提供了与队列模块中相似的队列类。目前为止,我们的例子中还没有使用到队列结构。在 chained.py 中的每一个 task(feature) 都由一组协程组成,这些协程都有一个单一的输入链,并显式的等待其它协程。

还有一种结构同样可以配合异步IO使用:许多互不关联的生产者将元素加入到一个队列中,每一个生产者可能在不同的时间,随机且无序的加入多个元素到队列中。还有一组消费者不管任何信号,不停地从队列中拉取元素。

这种设计中,任何一个生产者和消费者都没有关联。消费者事先并不知道生产者的数量,甚至不知道将累计添加的队列中的元素数。

它需要一个单独的生产者或消费者在一个可指定的时间内,分别向队列中放入或从队列中提取元素。生产者与消费者通过队列的吞吐进行通信,而不是两者直接通信。


注:由于 queue.Queue() 是线程安全的,所以它经常被用于开发基于线程的程序,而在异步IO编程中你不需要关心线程安全问题。(除非你将这两者合并在一起使用,但在本教程中并没有这么做。)

队列的一种用法(比如这里的情况)是充当生产者与消费者之间的通信通道,从而避免它们直接关联或联系。


这个程序的同步版本看起来有些让人不忍直视:一组生产者连续且阻塞的向队列中添加元素,一次只有一个生产者在工作。只有当所有生产者都运行结束,消费者才会从队列中一个接一个的取出元素并处理。这会造成大量的延时。元素可能会在队列中被搁置,而不是被立刻取出并处理。

而异步版本的程序 asyncq.py 如下所示。运行过程中的难点是向消费者发送生产者已经完成的信号。否则,await q.get() 将会因为队列已满而被无限挂起,但是消费者却不知道生产者已经完成的信息。

这里是全部的脚本文件:

几个协程作为辅助函数返回随机字符串,几分之一秒的性能计数器以及随机整数。生产者将1-5的元素放入队列中,每一个元素都是一个 (i, t) 的元组,其中 i 是一个随机字符串,t 是生产者尝试将元组放入队列所需要的时间。

当消费者从队列取出元素时,它只使用元素放入队列时所使用的时间戳计算耗费时间。

牢记 asyncio.sleep() 用于模仿其他复杂的协程,如果这里是常规阻塞函数,则会耗尽时间并阻塞其他所有函数的运行。

这里有一个实现了两个生产者和五个消费者的测试例子

这个例子中,元素在几分之一秒内被处理好,产生延时可能有两个原因:

1. 很大程度上不可避免的标准开销

2. 元素出现在队列中,而所有消费者都在睡眠的情况

幸运的是,关于第二个原因,正常情况下,将消费者扩展到成百上个也是允许的。你不应该对 python3 asyncq.py -p 5 -c 100 有什么疑问。这里有一点比较关键,理论上你可以使用不同的操作系统和用户来管理和控制生产者和消费者,而队列作为中间消息吞吐的媒介。

目前,你已经进入到异步IO的学习中,并且看到了三个由 async 和 await 定义的协程以及 asyncio 调用的相关示例。如果你只是想深入了解Python新式协程的实现机制,而并不是想全盘关注,下一节将会有一个直观的介绍。

英文原文:https://realpython.com/async-io-python/

译者:冰川

一、Python所有方向的学习路线

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,保证自己学得较为全面。

img
img

二、Python必备开发工具

工具都帮大家整理好了,安装就可直接上手!img

三、最新Python学习笔记

当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。

img

四、Python视频合集

观看全面零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

img

五、实战案例

纸上得来终觉浅,要学会跟着视频一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。img

六、面试宝典

在这里插入图片描述

在这里插入图片描述

简历模板在这里插入图片描述

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

g)

简历模板在这里插入图片描述

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值