5.异步

Posted traditional

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了5.异步相关的知识,希望对你有一定的参考价值。

终于到了传说中的异步了,感觉异步这个名字听起来就很酷酷的,以前还不是多擅长Python时,就跑去看twisted的源码,结果给我幼小的心灵留下了创伤。反正包括我在内,都知道异步编程很强大,但是却很少在项目中使用它,我自己使用异步也仅仅是在爬虫当中。而很多人一提到Python中的异步,首先想到的便是gevent,tornado,twisted这些框架。然而异步真的会经常出现问题,首先是编写异步代码难度较大,另一方面是经常会不小心把异步写成同步。因此在使用异步框架,很多人会感觉异步没厉害到哪去啊,其实是用法出现了问题,因此做web开发时,还是会选择Django或者flask。
现在的时代,主要是大数据的时代,但我认为,还是高并发的时代。go语言目前之所以这么火,便是因为其内部的goroutine,使得go语言在语言层面支持高并发,这也是go语言最大的卖点。当然Python也是一样,由Python之父在2013年开始亲自披挂上阵主持了asyncio的开发。关于asyncio模块,我之前也介绍过,可以去找一找。

因此在介绍tornado的异步之前,我会先介绍一下Python中的异步以及与相关的知识点。

-----------------------------------------------
部分内容参考于:https://mp.weixin.qq.com/s?__biz=MzIxMjY5NTE0MA==&mid=2247483720&idx=1&sn=f016c06ddd17765fd50b705fed64429c
-----------------------------------------------

1. 什么是异步编程

通过学习相关概念,我们逐步解释异步编程是什么

1.1 阻塞

程序未得到所需计算资源时,被挂起的状态
程序在等待某个操作完成期间,自身无法去干别的事情,则称程序在该操作上是阻塞的
常见的阻塞形式有:网络I/O阻塞,磁盘I/O阻塞,用户输入阻塞等等。
阻塞是无处不在的,包括cpu在切换上下文的时候,所有的进程都无法真正干事情,它们也会被阻塞。如果利用多核,那么正在执行上下文切换的核没有被利用

1.2 非阻塞

程序在等待某个操作完成期间,自身不被阻塞,可以继续干别的事情,则称程序在该操作上是不被阻塞的。
非阻塞并不是在任何程序级别,任何情况都可以存在的
仅当程序封装的级别可以囊括独立的程序子单元时,它才可能存在非阻塞状态。
非阻塞存在是因为阻塞存在,正因为某个阻塞操作导致的耗时与效率低下,所以我们才需要非阻塞。

1.3 同步

不同的程序单元为了完成某个任务,在执行过程中需要靠某种通信方式来协调一致,称这些程序单元是同步执行的。
例如购物系统中更新商品库存,需要使用“行锁”作为通信信号,让不同的更新请求强制排队顺序执行,那么更新库存的操作是同步的
简而言之,同步以为着有序

1.4 异步

为完成某个任务,不同程序单元之间执行过程中无需通信协调,也能完成任务的方式。
不相关的程序单元之间是可以异步的。
主要是有些操作是不耗费CPU的,那么在其处于等待状态,我们可以去执行其它的任务,当不阻塞了再回来执行。
例如,爬虫下载图片。首先要下载器要下载网页,然后spider进行解析图片的URL。然而调度器在调用下载程序之后,即可调度其它任务,而无需和下载器保持通信以协调行为。同理,spider进行解析图片的URL也无需和下载器保持通信。当我们在获取页面,等待服务器响应的这段时间,是阻塞的,那么我们可以利用这段时间来进行spider的解析。不同网页的下载和保存操作都是无关的,也无需相互通知相互协调,因此这些异步操作的完成时刻并不确定。
简而言之,异步意味着无序。

1.5 并发

在同一时间段有多个任务被CPU执行

1.6 并行

在同一时间点有多个任务被CPU执行

1.7 概念总结
并行:充分利用CPU的核数,同时执行多个任务。
并发:让所有的子任务都有机会被执行,因此如果是纯计算,那么当任务数超过CPU核数时,不一定能加速效率,因为要进行切换。但现如今大部分都是I/O操作,当阻塞时我去操作别的。
非阻塞:用于提高程序整体执行效率。
异步:高效的组织非阻塞任务的一种方式。
要保持高并发,必须拆分为多任务,不同任务相对而言,才会有阻塞/非阻塞,同步/异步。所以并发、异步、非阻塞三个词总是出现在一起。比方说异步,之所以用异步,不正是为了实现高并发吗?

1.8 异步编程
以进程、线程、协程、函数/方法作为执行程序的基本单位,结合回调、事件循环、信号量等机制,以提高程序整体执行效率和并发能力的编程方式
如果在某程序运行时,能根据已执行的指令,准确判断它接下来要执行那个具体操作,那它便是同步程序,反之成为异步程序(无序和有序的区别)
同步/异步,阻塞/非阻塞之间并非水火不容,要看程序所处的封装级别。例如购物程序在处理的用户的浏览请求可以是同步的,而更新库存则必须是同步的。

1.9 异步之难与回调之痛
和多线程不一样,线程之间的切换是由操作系统调度的,而协程的切换是由程序员决定的。正是因为如此,我控制不住我自己啊,一旦出了问题,要想找出来bug是非常困难的。同步是顺序执行的,如果出错,可以很快的找出问题。然而异步,要想找出问题,会很麻烦。而且在并行情况下,会更痛苦
所以,几乎所有的异步框架都将异步编程模型简化,因此现在关于异步的讨论都集中了单线程内。
如果某个任务处理需要花费很长的时间,那么其他的部分会被阻塞。
所以一旦采取了异步编程,每个异步调用必须足够小,不能耗时太久,否则其他部分无法执行。那么如何将异步任务进行拆分便成了难题。
程序的下一步的输入往往以来上一步的输出,如何知晓上一步异步调用已完成并获取结果。
因此callback则成了必然的选择,那又要面临回调的折磨。
同步代码改为异步代码,必然会破坏代码结构。
所以程序员更喜欢使用同步的方式,编写异步代码。改变解决问题的逻辑,不要一条路走到黑,要精心安排设计任务。

2. 如此煞费苦心于异步,究竟所为哪般?

如上面所述,异步编程面临诸多难点,Python之父亲自上阵打磨4年才使得asyncio模块,在Python3.6中正式转正。如此苦心是为何?因为:值得。让我们看看为什么值得。

2.1 CPU的时间观

我们将一个2.6GHz的CPU 拟人化,如果延迟了0.38纳秒,CPU感觉像是过了1秒。CPU是计算机的处理核心,也是最宝贵的资源,如果有浪费CPU的运行时间,导致其利用率不足,那么程序的效率必然低下,因为实际上还有资源可以使效率更高。
在千兆网传输2KB数据,如果延迟20微妙,CPU感觉过了14.4个小时。从SSD读取1M连续数据,用1毫秒,CPU感觉过了1个月。在这么长的时间里,CPU只能傻等着而不能做其他事情,这岂不是在浪费CPU的青春。
我国的白学家鲁迅也说过:“浪费CPU的时间等于谋财害命,而凶手就是程序员”

技术分享图片

 

2.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 协程

协程(Co-routine),即是协作式的例程。

它是非抢占式的多任务子例程的概括,可以允许有多个入口点在例程中确定的位置来控制程序的暂停与恢复执行。

例程是什么?编程语言定义的可被调用的代码段,为了完成某个特定功能而封装在一起的一系列指令。一般的编程语言都用称为函数或方法的代码结构来体现

3.1 基于生成器的协程

 


































以上是关于5.异步的主要内容,如果未能解决你的问题,请参考以下文章

Vuex 第5节 actions异步修改状态

C# 5.0 特性之异步方法(AM)

javascript的异步编程解决方案收集

我正在使用 asyncio,但异步函数正在使用 await asyncio.sleep(5) 阻塞其他异步函数

Java异步调用转同步的5种方式

5分钟了解PHP异步编程