没有合适的资源?快使用搜索试试~ 我知道了~
前言很多朋友对异步编程都处于“听说很强大”的认知状态。鲜有在生产项目中使用它。而使用它的同学,则大多数都停留在知道如何使用Tornado、Twisted、Gev
资源详情
资源评论
资源推荐
Earendil
深入理解 Python 异步编程(上)
http://python.jobbole.com/88291/
前言
很多朋友对异步编程都处于“听说很强大”的认知状态。鲜有在生产项目中使用它。而使用它的同学,则大多数都停留在知道如何使用
Tornado、Twisted、Gevent 这类异步框架上,出现各种古怪的问题难以解决。而且使用了异步框架的部分同学,由于用法不对,感觉它并
没牛逼到哪里去,所以很多同学做 Web 后端服务时还是采用 Flask、Django等传统的非异步框架。
从上两届 PyCon 技术大会看来,异步编程已经成了 Python 生态下一阶段的主旋律。如新兴的 Go、Rust、Elixir 等编程语言都将其支持异
步和高并发作为主要“卖点”,技术变化趋势如此。Python 生态为不落人后,从2013年起由 Python 之父 Guido 亲自操刀主持了
Tulip(asyncio)项目的开发。
本系列教程分为上中下篇,让读者深入理解Python异步编程,解决在使用异步编程中的疑惑,深入学习Python3中新增的asyncio库和
async/await语法,尽情享受 Python 带来的简洁优雅和高效率。
内容安排
上篇
了解 异步编程及其紧密相关的概念,如阻塞/非阻塞、同步/异步、并发/并行等
理解 异步编程是什么,以及异步编程的困难之处
理解 为什么需要异步编程
熟悉 如何从同步阻塞发展到异步非阻塞的
掌握epoll + Callback + Event loop是如何工作的
掌握 Python 是如何逐步从回调到生成器再到原生协程以支持异步编程的
掌握 asyncio 的工作原理
中篇
掌握 asyncio 标准库基本使用
掌握 asyncio 的事件循环
掌握 协程与任务如何使用与管理(如调度与取消调度)
掌握 同步原语的使用(Lock、Event、Condition、Queue)
掌握 asyncio 和多进程、多线程结合使用
下篇
理解 GIL 对异步编程的影响
理解 asyncio 踩坑经验
理解 回调、协程、绿程(Green-Thread)、线程对比总结
掌握 多进程、多线程、协程各自的适用场景
了解 Gevent/libev、uvloop/libuv 与asyncio的区别和联系
掌握 Python异步编程的一些指导细则
1 什么是异步编程
通过学习相关概念,我们逐步解释异步编程是什么。
1.1 阻塞
程序未得到所需计算资源时被挂起的状态。
程序在等待某个操作完成期间,自身无法继续干别的事情,则称该程序在该操作上是阻塞的。
常见的阻塞形式有:网络I/O阻塞、磁盘I/O阻塞、用户输入阻塞等。
阻塞是无处不在的,包括CPU切换上下文时,所有的进程都无法真正干事情,它们也会被阻塞。(如果是多核CPU则正在执行上下文切换操
作的核不可被利用。)
1.2 非阻塞
程序在等待某操作过程中,自身不被阻塞,可以继续运行干别的事情,则称该程序在该操作上是非阻塞的。
非阻塞并不是在任何程序级别、任何情况下都可以存在的。
仅当程序封装的级别可以囊括独立的子程序单元时,它才可能存在非阻塞状态。
非阻塞的存在是因为阻塞存在,正因为某个操作阻塞导致的耗时与效率低下,我们才要把它变成非阻塞的。
1.3 同步
不同程序单元为了完成某个任务,在执行过程中需靠某种通信方式以协调一致,称这些程序单元是同步执行的。
博客园 首页 新随笔 联系 订阅 管理
随笔-111 文章-0 评论-5
公告
昵称:Earendil
园龄:3年7个月
粉丝:7
关注:1
+加关注
< 2018年2月 >
日 一 二 三 四 五 六
28 29 30 31 1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 1 2 3
4 5 6 7 8 9 10
搜索
找找看
谷歌搜索
常用链接
我的随笔
我的评论
我的参与
最新评论
我的标签
我的标签
Android adb shell(1)
android 传感器(1)
随笔分类
git(1)
JAVA(10)
redis(2)
SQL(2)
操作系统(1)
大数据(1)
算法(15)
随笔档案
2018年1月 (12)
2017年12月 (12)
2017年11月 (1)
2017年9月 (1)
2017年8月 (9)
2017年7月 (2)
2017年6月 (1)
2017年5月 (3)
2017年4月 (6)
2017年3月 (5)
2017年2月 (5)
2017年1月 (1)
2016年12月 (1)
2016年8月 (1)
2016年6月 (8)
2015年12月 (5)
2015年6月 (2)
2015年5月 (3)
2015年4月 (4)
2015年3月 (3)
2015年2月 (1)
2015年1月 (4)
2014年12月 (1)
2014年10月 (5)
2014年9月 (11)
2014年7月 (4)
深入理解 Python 异步编程(上) - Earendil - 博客园 https://www.cnblogs.com/earendil/p/7411115.html
第1页 共21页 2018/2/2 13:24
例如购物系统中更新商品库存,需要用“行锁”作为通信信号,让不同的更新请求强制排队顺序执行,那更新库存的操作是同步的。
简言之,同步意味着有序。
1.4 异步
为完成某个任务,不同程序单元之间过程中无需通信协调,也能完成任务的方式。
不相关的程序单元之间可以是异步的。
例如,爬虫下载网页。调度程序调用下载程序后,即可调度其他任务,而无需与该下载任务保持通信以协调行为。不同网页的下载、保
存等操作都是无关的,也无需相互通知协调。这些异步操作的完成时刻并不确定。
简言之,异步意味着无序。
上文提到的“通信方式”通常是指异步和并发编程提供的同步原语,如信号量、锁、同步队列等等。我们需知道,虽然这些通信方式是为了让
多个程序在一定条件下同步执行,但正因为是异步的存在,才需要这些通信方式。如果所有程序都是按序执行,其本身就是同步的,又何需
这些同步信号呢?
1.5 并发
并发描述的是程序的组织结构。指程序要被设计成多个可独立执行的子任务。
以利用有限的计算机资源使多个任务可以被实时或近实时执行为目的。
1.6 并行
并行描述的是程序的执行状态。指多个任务同时被执行。
以利用富余计算资源(多核CPU)加速完成多个任务为目的。
并发提供了一种程序组织结构方式,让问题的解决方案可以并行执行,但并行执行不是必须的。
1.7 概念总结
并行是为了利用多核加速多任务完成的进度
并发是为了让独立的子任务都有机会被尽快执行,但不一定能加速整体进度
非阻塞是为了提高程序整体执行效率
异步是高效地组织非阻塞任务的方式
要支持并发,必须拆分为多任务,不同任务相对而言才有阻塞/非阻塞、同步/异步。所以,并发、异步、非阻塞三个词总是如影随形。
1.8 异步编程
以进程、线程、协程、函数/方法作为执行任务程序的基本单位,结合回调、事件循环、信号量等机制,以提高程序整体执行效率和并发
能力的编程方式。
如果在某程序的运行时,能根据已经执行的指令准确判断它接下来要进行哪个具体操作,那它是同步程序,反之则为异步程序。(无序与有
序的区别)
同步/异步、阻塞/非阻塞并非水火不容,要看讨论的程序所处的封装级别。例如购物程序在处理多个用户的浏览请求可以是异步的,而更新
库存时必须是同步的。
1.9 异步之难(nán)
控制不住“计几”写的程序,因为其执行顺序不可预料,当下正要发生什么事件不可预料。在并行情况下更为复杂和艰难。
所以,几乎所有的异步框架都将异步编程模型简化:一次只允许处理一个事件。故而有关异步的讨论几乎都集中在了单线程内。
如果某事件处理程序需要长时间执行,所有其他部分都会被阻塞。
所以,一旦采取异步编程,每个异步调用必须“足够小”,不能耗时太久。如何拆分异步任务成了难题。
程序下一步行为往往依赖上一步执行结果,如何知晓上次异步调用已完成并获取结果?
回调(Callback)成了必然选择。那又需要面临“回调地狱”的折磨。
同步代码改为异步代码,必然破坏代码结构。
解决问题的逻辑也要转变,不再是一条路走到黑,需要精心安排异步任务。
2 苦心异步为哪般
如上文所述,异步编程面临诸多难点,Python 之父亲自上阵打磨4年才使 asyncio 模块在Python 3.6中“转正”,如此苦心为什么?答案只
有一个:它值得!下面我们看看为何而值得。
2.1 CPU的时间观
最新评论
1. Re:机器学习实战 第五章 罗辑回归
的 代价函数推导
假设 y= a(theta)^2+b(theta)+c,已
知 x 和 y 矩阵,可以求出theta =
(x'x)^-1x'y一次性可以求出,不用学习
速率,以及迭代,但是只适用于 样本量
比较小的时候,......
--BUTTERAPPLE
2. Re:机器学习实战 第五章 罗辑回归
的 代价函数推导
@BUTTERAPPLE请问标准方程法值得
是用最小二乘法吗?...
--Earendil
3. Re:机器学习实战 第五章 罗辑回归
的 代价函数推导
样本数量不是太大的话,用标准方程法效
率略高于梯度下降。
--BUTTERAPPLE
4. Re:KD树
@阿里嘎多coder谢谢了...
--Earendil
5. Re:KD树
关于kd树 看看这篇文章吧 说的非常详
细 还有代码实现
--阿里嘎多coder
阅读排行榜
1. 深入理解 Python 异步编程(上)
(2932)
2. 【转】搭建spark环境 单机版(2367)
3. 【原创】java NIO FileChannel 学
习笔记 FileChannel 简介(1244)
4. 【转】java jvm 线程 与操作系统线
程(1101)
5. Android源码下载和编译过程(742)
评论排行榜
1. 机器学习实战 第五章 罗辑回归 的 代
价函数推导(3)
2. KD树(2)
推荐排行榜
1. 深入理解 Python 异步编程(上)(5)
2. Android源码下载和编译过程(2)
3. 【原创】java NIO FileChannel 学
习笔记 新建一个FileChannel(1)
深入理解 Python 异步编程(上) - Earendil - 博客园 https://www.cnblogs.com/earendil/p/7411115.html
第2页 共21页 2018/2/2 13:24
我们将一个 2.6GHz 的 CPU 拟人化,假设它执行一条命令的时间,他它感觉上过了一秒钟。CPU是计算机的处理核心,也是最宝贵的资
源,如果有浪费CPU的运行时间,导致其利用率不足,那程序效率必然低下(因为实际上有资源可以使效率更高)。
如上图所示,在千兆网上传输2KB数据,CPU感觉过了14个小时,如果是在10M的公网上呢?那效率会低百倍!如果在这么长的一段时间
内,CPU只是傻等结果而不能去干其他事情,是不是在浪费CPU的青春?
深入理解 Python 异步编程(上) - Earendil - 博客园 https://www.cnblogs.com/earendil/p/7411115.html
第3页 共21页 2018/2/2 13:24
鲁迅说,浪费“CPU”的时间等于谋财害命。而凶手就是程序猿。
2.2 面临的问题
成本问题
如果一个程序不能有效利用一台计算机资源,那必然需要更多的计算机通过运行更多的程序实例来弥补需求缺口。例如我前不久主导重写的
项目,使用Python异步编程,改版后由原来的7台服务器削减至3台,成本骤降57%。一台AWS m4.xlarge 型通用服务器按需付费实例一
年价格约 1.2 万人民币。
效率问题
如果不在乎钱的消耗,那也会在意效率问题。当服务器数量堆叠到一定规模后,如果不改进软件架构和实现,加机器是徒劳,而且运维成本
会骤然增加。比如别人家的电商平台支持6000单/秒支付,而自家在下单量才支撑2000单/秒,在双十一这种活动的时候,钱送上门也赚不
到。
C10k/C10M挑战
C10k(concurrently handling 10k connections)是一个在1999年被提出来的技术挑战,如何在一颗1GHz CPU,2G内存,1gbps网
络环境下,让单台服务器同时为1万个客户端提供FTP服务。而到了2010年后,随着硬件技术的发展,这个问题被延伸为C10M,即如何利用
8核心CPU,64G内存,在10gbps的网络上保持1000万并发连接,或是每秒钟处理100万的连接。(两种类型的计算机资源在各自的时代都
约为1200美元)
成本和效率问题是从企业经营角度讲,C10k/C10M问题则是从技术角度出发挑战软硬件极限。C10k/C10M 问题得解,成本问题和效率问
题迎刃而解。
2.3 解决方案
《约束理论与企业优化》中指出:“除了瓶颈之外,任何改进都是幻觉。”
CPU告诉我们,它自己很快,而上下文切换慢、内存读数据慢、磁盘寻址与取数据慢、网络传输慢……总之,离开CPU 后的一切,除了一级
高速缓存,都很慢。我们观察计算机的组成可以知道,主要由运算器、控制器、存储器、输入设备、输出设备五部分组成。运算器和控制器
主要集成在CPU中,除此之外全是I/O,包括读写内存、读写磁盘、读写网卡全都是I/O。I/O成了最大的瓶颈。
异步程序可以提高效率,而最大的瓶颈在I/O,业界诞生的解决方案没出意料:异步I/O吧,异步I/O吧,异步I/O吧吧!
3 异步I/O进化之路
如今,地球上最发达、规模最庞大的计算机程序,莫过于因特网。而从CPU的时间观中可知,网络I/O是最大的I/O瓶颈,除了宕机没有比
它更慢的。所以,诸多异步框架都对准的是网络I/O。
我们从一个爬虫例子说起,从因特网上下载10篇网页。
3.1 同步阻塞方式
最容易想到的解决方案就是依次下载,从建立socket连接到发送网络请求再到读取响应数据,顺序进行。
深入理解 Python 异步编程(上) - Earendil - 博客园 https://www.cnblogs.com/earendil/p/7411115.html
第4页 共21页 2018/2/2 13:24
注:总体耗时约为4.5秒。(因网络波动每次测试结果有所变动,本文取多次平均值)
如上图所示,blocking_way() 的作用是建立 socket 连接,发送HTTP请求,然后从 socket读取HTTP响应并返回数据。示例中我们请求
了 example.com 的首页。在sync_way() 执行了10次,即下载 example.com 首页10次。
在示例代码中有两个关键点。一是第10行的 sock.connect((‘example.com’, 80)),该调用的作用是向example.com主机的80端
口发起网络连接请求。 二是第14行、第18行的sock.recv(4096),该调用的作用是从socket上读取4K字节数据。
我们知道,创建网络连接,多久能创建完成不是客户端决定的,而是由网络状况和服务端处理能力共同决定。服务端什么时候返回了响应数
据并被客户端接收到可供程序读取,也是不可预测的。所以sock.connect()和sock.recv()这两个调用在默认情况下是阻塞的。
注:sock.send()函数并不会阻塞太久,它只负责将请求数据拷贝到TCP/IP协议栈的系统缓冲区中就返回,并不等待服务端返回的应答
确认。
假设网络环境很差,创建网络连接需要1秒钟,那么sock.connect()就得阻塞1秒钟,等待网络连接成功。这1秒钟对一颗2.6GHz的CPU
来讲,仿佛过去了83年,然而它不能干任何事情。sock.recv()也是一样的必须得等到服务端的响应数据已经被客户端接收。我们下载10
篇网页,这个阻塞过程就得重复10次。如果一个爬虫系统每天要下载1000万篇网页呢?!
上面说了很多,我们力图说明一件事:同步阻塞的网络交互方式,效率低十分低下。特别是在网络交互频繁的程序中。这种方式根本不可能
挑战C10K/C10M。
3.2 改进方式:多进程
在一个程序内,依次执行10次太耗时,那开10个一样的程序同时执行不就行了。于是我们想到了多进程编程。为什么会先想到多进程呢?发
展脉络如此。在更早的操作系统(Linux 2.4)及其以前,进程是 OS 调度任务的实体,是面向进程设计的OS。
深入理解 Python 异步编程(上) - Earendil - 博客园 https://www.cnblogs.com/earendil/p/7411115.html
第5页 共21页 2018/2/2 13:24
剩余20页未读,继续阅读
以墨健康道
- 粉丝: 25
- 资源: 307
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 基于matlab实现用有限元法计算电磁场的Matlab工具 .rar
- 基于matlab实现有限元算法 计算电磁场问题 边界条件包括第一类边界和第二类边界.rar
- 基于matlab实现用于计算不同车重下的电动汽车动力性和经济性.rar
- 基于matlab实现遗传算法求解多车场车辆路径问题 有多组算例可以用.rar
- 浏览器.apk
- 基于matlab实现是一个matlab中的power system 中搭建的一个模型
- 基于JSP毕业设计-教学管理系统(源代码+论文).zip
- 基于JSP毕业设计-家政管理系统-毕业设计.zip
- 基于Python实现淘宝商品评论采集(含逆向)源代码
- 基于matlab实现多目标进化算法NSGAⅡ&Matlab讲解.rar
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0