摘要:并发的方式有多种,多线程,多进程,异步等。多线程和多进程之间的场景切换和通讯代价很高,不适合密集型的场景关于多线程和多进程的特点已经超出本文讨论的范畴,有兴趣的同学可以自行搜索深入理解。
编程中,我们经常会遇到“并发”这个概念,目的是让软件能充分利用硬件资源,提高性能。并发的方式有多种,多线程,多进程,异步IO等。多线程和多进程更多应用于CPU密集型的场景,比如科学计算的时间都耗费在CPU上,利用多核CPU来分担计算任务。多线程和多进程之间的场景切换和通讯代价很高,不适合IO密集型的场景(关于多线程和多进程的特点已经超出本文讨论的范畴,有兴趣的同学可以自行搜索深入理解)。而异步IO就是非常适合IO密集型的场景,比如网络爬虫和Web服务。
在计算机程序中,IO就是读写磁盘、读写网络的操作,这种读写速度比读写内存、CPU缓存慢得多,前者的耗时是后者的成千上万倍甚至更多。这就导致,IO密集型的场景99%以上的时间都花费在IO等待的时间上。异步IO就是把CPU从漫长的等待中解放出来的方法。这就可以大大提高我们写的软件系统的并发性。这样的软件,可以是网络爬虫,也可以是Web服务等一切IO密集型的系统。
异步IO的优势显而易见,各种语言都通过实现这个机制来提高自身的效率,Python也不例外。Python经历了2和3两个大版本的跃迁。这其中也有对异步IO支持的变化历程。
Python 2的异步IO库Python 2 时代官方并没有异步IO的支持,但是有几个第三方库通过事件或事件循环(Event Loop)实现了异步IO,它们是:
twisted: 是事件驱动的网络库
gevent: greenlet + libevent(后来是libev或libuv)。通过协程(greenlet)和事件循环库(libev,libuv)实现的gevent使用很广泛。
tornado: 支持异步IO的web框架。自己实现了IOLOOP。
Python 3 官方的异步IOPython 3.4 加入了asyncio 库,使得Python有了支持异步IO的官方库。这个库,底层是事件循环(EventLoop),上层是协程和任务。asyncio自从3.4 版本加入到最新的 3.7版一直在改进中。
Python 3.4 刚开始的asyncio的协程还是基于生成器的,通过 yield from 语法实现,可以通过装饰器 @asyncio.coroutine (已过时)装饰一个函数来定义一个协程。比如:
Python 3.5 引入了两个新的关键字 await 和 async 用来替换 @asyncio.coroutine 和 yield from ,从语言本身来支持异步IO。从而使得异步编程更加简洁,并和普通的生成器区别开来。
注意: 对基于生成器的协程的支持已弃用,并计划在 Python 3.10 中移除。所以,写异步IO程序时只需使用 async 和 await 即可。
Python 3.7 又进行了优化,把API分组为高层级API和低层级API。 我们先看看下面的代码,发现与上面的有什么不同?
除了用 async 替换 @asyncio.coroutine 和用 await 替换 yield from 外,最大的变化就是关于eventloop的代码不见了,只有一个 async.run()。这就是 3.7 的改进,把eventloop相关的API归入到低层级API,新引进run()作为高层级API让写应用程序的开发者调用,而不用再关心eventloop。除非你要写异步库(比如MySQL异步库)才会和eventloop打交道。
需要注意的是, async.run() 是3.7版新增加的,处于暂定API状态。 暂定API,是指被有意排除在标准库的向后兼容性保证之外的应用编程接口。虽然此类接口通常不会再有重大改变,但只要其被标记为暂定,就可能在核心开发者确定有必要的情况下进行向后不兼容的更改(甚至包括移除该接口)。此种更改并不会随意进行 — 仅在 API 被加入之前未考虑到的严重基础性缺陷被发现时才可能会这样做。即便是对暂定 API 来说,向后不兼容的更改也会被视为“最后的解决方案” —— 任何问题被确认时都会尽可能先尝试找到一种向后兼容的解决方案。这种处理过程允许标准库持续不断地演进,不至于被有问题的长期性设计缺陷所困。
从上面关于 asyncio 的发展来看它一直在变化,3.4,3.5,3.6, 3.7 都有很多细节上的变化。当我看到3.7的run()函数时,也发现一年前基于3.6的asnycio写的爬虫不那么优雅了。
这种变化,一方面改善了asyncio本身的性能和使用方便程度,但另一方面也增加了我们使用者的学习成本、Python升级带来的改造的成本。如果你以消极的态度抵制这种变化,可以去学习golang,C++来实现你的程序;如果你以积极的态度迎接这种变化,可以更快的掌握这种变化,并优雅 高效的实现你的程序。
只要你喜欢用Python写程序解决问题,那么就接受并掌握这种变化吧。其实,那种语言不在变,那种技术不在前进。作为程序员,你只有不断地学习和前进。
uvloopuvloop是用Cython写的,基于libuv这个C语言实现的高性能异步I/O库。asyncio自己的事件循环是用Python写的,用uvloop替换asyncio自己的事件循环可以是asyncio的速度更快。并且使用相当简洁:
大家在学python的时候肯定会遇到很多难题,以及对于新技术的追求,这里推荐一下我们的Python学习扣qun:784758214,这里是python学习者聚集地!!同时,自己是一名高级python开发工程师,从基础的python脚本到web开发、爬虫、django、数据挖掘等,零基础到项目实战的资料都有整理。送给每一位python的小伙伴!每日分享一些学习的方法和需要注意的小细节
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/43839.html
摘要:具有以下基本同步原语子进程提供了通过创建和管理子进程的。虽然队列不是线程安全的,但它们被设计为专门用于代码。表示异步操作的最终结果。 Python的asyncio是使用 async/await 语法编写并发代码的标准库。通过上一节的讲解,我们了解了它不断变化的发展历史。到了Python最新稳定版 3.7 这个版本,asyncio又做了比较大的调整,把这个库的API分为了 高层级API和...
摘要:创建第一个协程推荐使用语法来声明协程,来编写异步应用程序。协程两个紧密相关的概念是协程函数通过定义的函数协程对象调用协程函数返回的对象。它是一个低层级的可等待对象,表示一个异步操作的最终结果。 我们讲以Python 3.7 上的asyncio为例讲解如何使用Python的异步IO。 showImg(https://segmentfault.com/img/remote/14600000...
摘要:理解迭代对象迭代器生成器后端掘金本文源自作者的一篇博文,原文是,俺写的这篇文章是按照自己的理解做的参考翻译。比较的是两个对象的内容是后端掘金黑魔法之协程异步后端掘金本文为作者原创,转载请先与作者联系。 完全理解关键字with与上下文管理器 - 掘金如果你有阅读源码的习惯,可能会看到一些优秀的代码经常出现带有 with 关键字的语句,它通常用在什么场景呢?今天就来说说 with 和 上下...
摘要:前端每周清单专注前端领域内容,以对外文资料的搜集为主,帮助开发者了解一周前端热点分为新闻热点开发教程工程实践深度阅读开源项目巅峰人生等栏目。背后的故事本文是对于年之间世界发生的大事件的详细介绍,阐述了从提出到角力到流产的前世今生。 前端每周清单专注前端领域内容,以对外文资料的搜集为主,帮助开发者了解一周前端热点;分为新闻热点、开发教程、工程实践、深度阅读、开源项目、巅峰人生等栏目。欢迎...
阅读 1874·2021-09-28 09:36
阅读 2424·2021-09-08 09:35
阅读 3065·2019-08-30 15:53
阅读 1552·2019-08-30 14:08
阅读 663·2019-08-29 18:40
阅读 2842·2019-08-29 13:57
阅读 2700·2019-08-29 13:55
阅读 680·2019-08-26 13:45