Python基础之进程、线程、协程及IO多路复用
详情戳击下方链接
学习进程、线程、协程,引申一些内容
为什么要学习进程和线程:
进程和线程目的是为了:提高执行效率
现代操作系统比如Mac OS X,UNIX,Linux,Windows等,都是支持“多任务”的操作系统。
什么叫“多任务“呢?简单地说,就是操作系统可以同时运行多个任务。打个比方,你一边在用浏览器上网,一边在听MP3,一边在用Word赶作业,这就是多任务,至少同时有3个任务正在运行。还有很多任务悄悄地在后台同时运行着,只是桌面上没有显示而已。
现在,多核CPU已经非常普及了,但是,即使过去的单核CPU,也可以执行多任务。由于CPU执行代码都是顺序执行的,那么,单核CPU是怎么执行多任务的呢?
答案就是操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换到任务2,任务2执行0.01秒,再切换到任务3,执行0.01秒……这样反复执行下去。表面上看,每个任务都是交替执行的,但是,由于CPU的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样。
真正的并行执行多任务只能在多核CPU上实现,但是,由于任务数量远远多于CPU的核心数量,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行。
对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,打开一个Word就启动了一个Word进程。
有些进程还不止同时干一件事,比如Word,它可以同时进行打字、拼写检查、打印等事情。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread)。
由于每个进程至少要干一件事,所以,一个进程至少有一个线程。当然,像Word这种复杂的进程可以有多个线程,多个线程可以同时执行,多线程的执行方式和多进程是一样的,也是由操作系统在多个线程之间快速切换,让每个线程都短暂地交替运行,看起来就像同时执行一样。当然,真正地同时执行多线程需要多核CPU才可能实现。
我们前面编写的所有的Python程序,都是执行单任务的进程,也就是只有一个线程。如果我们要同时执行多个任务怎么办?
有两种解决方案:
一种是启动多个进程,每个进程虽然只有一个线程,但多个进程可以一块执行多个任务。
还有一种方法是启动一个进程,在一个进程内启动多个线程,这样,多个线程也可以一块执行多个任务。
当然还有第三种方法,就是启动多个进程,每个进程再启动多个线程,这样同时执行的任务就更多了,当然这种模型更复杂,实际很少采用。
总结一下就是,多任务的实现有3种方式:
- 多进程模式;
- 多线程模式;
- 多进程+多线程模式。
同时执行多个任务通常各个任务之间并不是没有关联的,而是需要相互通信和协调,有时,任务1必须暂停等待任务2完成后才能继续执行,有时,任务3和任务4又不能同时执行,所以,多进程和多线程的程序的复杂度要远远高于我们前面写的单进程单线程的程序。
因为复杂度高,调试困难,所以,不是迫不得已,我们也不想编写多任务。但是,有很多时候,没有多任务还真不行。想想在电脑上看电影,就必须由一个线程播放视频,另一个线程播放音频,否则,单线程实现的话就只能先把视频播放完再播放音频,或者先把音频播放完再播放视频,这显然是不行的。
Python既支持多进程,又支持多线程,我们会讨论如何编写这两种多任务程序。
小结
线程是最小的执行单元,而进程由至少一个线程组成。如何调度进程和线程,完全由操作系统决定,程序自己不能决定什么时候执行,执行多长时间。
多进程和多线程的程序涉及到同步、数据共享的问题,编写起来更复杂。
总之一句话,具体案例具体分析。需要根据实际的情况,精准的定位问题的所在,而不会盲目去做方案
并发 & 并行
并发 : 是指系统具有处理多个任务(动作)的能力
并行 : 是指系统具有 同时 处理多个任务(动作)的能力
并行是不是并发的一个子集
同步 与 异步
同步: 当进程执行到一个IO(等待外部数据)的时候,------等:同步
异步: ------不等:一直等到数据接收成功,再回来处理
任务: IO密集型
计算密集型
对于IO密集型的任务 : python的多线程的是有意义的
可以采用多进程+协程
对于计算密集型的任务: python的多线程就不推荐,python就不适用了。当然了可以用进程,也可以改C
俩种任务为何有不同的针对性,在学习完进程、线程结束之后就会知道为何这样了
进程不是越多越好,线程自然也不是越多越好,具体案例具体分析,请求上下文耗时
计算机操作系统发展史
简单来说,可以概述说计算机一共发展了四代
为什么要有操作系统?
现代计算机系统是由一个或者多个处理器,主存,磁盘,打印机,键盘,鼠标显示器,网络接口以及各种其他输入
输出设备组成的复杂系统,每位程序员不可能掌握所有系统实现的细节,并且管理优化这些部件是一件挑战性极强
的工作。所以,我们需要为计算机安装一层软件,成为操作系统,任务就是用户程序提供一个简单清晰的计算机模
型,并管理以上所有设备。
定义也就有了:操作系统是一个用来协调、管理和控制计算机硬件和软件资源的系统程序,它位于硬件和应用程序之间。
(程序是运行在系统上的具有某种功能的软件,比如说浏览器,音乐播放器等。)
操作系统的内核的定义:操作系统的内核是一个管理和控制程序,负责管理计算机的所有物理资源,其中包括:文件系
统、内存管理、设备管理和进程管理。
一、真空管与穿孔卡片(无操作系统)
过程:
万能程序员们将对应于程序和数据的已穿孔的纸带(或卡片)装入输入机,然后启动输入机把程序和数据输入计算机
内存,接着通过控制台开关启动程序针对数据运行;计算完毕,打印机输出计算结果;用户取走结果并卸下纸带(或
卡片)后,才让下一个用户上机。
注意点:
程序员需要在墙上的计时表上预约时间
同一时刻只有一个程序在内存中被CPU调用运行(串行的)
优缺点:
优点:程序员在申请的时间段内独享整个资源,即时的调试自己的程序,如果有bug可以当场处理,
缺点:这对于计算机提供商来说是一种浪费(你买一台电脑4000块,那 一年中你用365比只用1天,肯定是省成本的,
物尽其用)
二、晶体管和批处理系统
一代计算机的问题: 人机交互太多了(输入--->计算--->输出 输入--->计算--->输出 输入--->计算--->输出 ) 解决办法: 把一堆人的输入攒成一大波输入,然后顺序计算(这是有问题的,但是第二代计算没有解决)再把计算结果攒成 一大波输出,这就是批处理系统 操作系统前身: 在收集了大约一个小时的批量作业之后,这些卡片被读入磁带,然后磁带被送到机房里并装到磁带上。然后磁带被送到 机房里并装到磁带机上。随后,操作员装入一个特殊的程序(此乃现代操作系统的前身),它负责从磁带上读入第一个 作业(job,一个或一组程序)并运行,其输出写到第二个磁带上,而且不打印。每个作业结束后,操作系统自动的从 磁带上读入下一个作业并且运行。当一整批的作业全部结束后,操作员去下输入和输出磁带,讲输入磁带换成下一批作 业,并且把输出磁带拿到一台1041机器上进行脱机(不与主计算机联机)打印 优点:批处理 缺点: 1 图的中间还有俩小人 2 仍然是顺序计算
三、集成电路芯片和多道程序设计
针对二代计算机的两个主要问题 开发出SPOOLING技术: 卡片被拿到机房后能够很快的将作业从卡片读入磁盘,于是任何时刻当一个作业结束时,操作系统就能将一个作业从磁 带读出,装进空出啦的内存区域运行,这种技术叫做同时的外部设备联机操作:SPOOLING该技术同时用于输出。当采 用了这种技术后,就不在需要IBM1401机了,也不必将磁带搬来搬去了(中间俩小人失业了),强化了操作系统的功能 开发出多道程序设计,用于解决顺序执行的问题: 在7094机上(程序运行的机器),若当前作业因等待磁带或等待其他IO操作而暂停,CPU就处于休闲状态直至IO操作 完成,对于CPU密集的科学计算,IO操作少,浪费时间不明显,对于商业数据处理,IO等待能到达80%~90%,所以必 须解决CPU浪费的现象。 解决方案:将内存分为几个部分,每一部分存放不同的作业,如图1-5所示。当一个作业等待IO完成时,另一个作业可以 使用CPU,内存中放足够的作业,则CPU的利用率能接近100% 此时的第三代计算机适合大型科学计算和繁忙的商务数据处理,但,本质上其仍是一个批处理系统。 虽然解决了诸如以上问题,但多个作业必须在全部运行结束后,才能得到结果,从一个作业的提交到运算结果取回往往 长达数小时。 想象一个场景:A君 B君 C君 三个程序员同时在调试程序,一旦A君写错一个逗号,那么可能需要半天的时间才能看到结 果,因为B君C君的结果也同时运算出来了。时间必然要长。一言以蔽之:大家一起存作业,大家一起去数据(磁带) 许多程序员怀念第一代独享的计算机,可以即时调试自己的程序。为了满足程序员们很快可以得到响应,出现了分时操作系统 分时操作系统:多个联机终端+多道技术 20个客户端同时加载到内存,有17在思考,3个在运行,cpu就采用多道的方式处理内存中的这3个程序,由于客户提交的一般 都是简短的指令而且很少有耗时长的,索引计算机能够为许多用户提供快速的交互式服务,所有的用户都以为自己独享了计 算机资源
四、个人计算机
随着大规模集成电路的发展,每平方厘米的硅片芯片上可以集成数千个晶体管,个人计算机的时代就此到来。
五、需要知道的东西
每个cpu都有其一套可执行的专门指令集,如SPARC和Pentium,其实每个硬件之上都要有一个控制程序,cpu的指令集就是cpu的控制程序。
内核态于与用户态指的是计算机的两种工作状态
即cpu的两种工作状态
(现在的操作系统都是分时操作系统,分时的根源来自于硬件层面操作系统内核占用的内存与应用程序占用的内存彼此之间隔离)
cpu通过psw(程序状态寄存器)中的一个2进制位来控制cpu本身的工作状态,即内核态与用户态。
内核态:操作系统内核只能运作于cpu的内核态,这种状态意味着可以执行cpu所有的指令,可以执行cpu所有的指令,这也意味着对计算机硬件资源有着完全的控制权限,并且可以控制cpu工作状态由内核态转成用户态。
用户态:应用程序只能运作于cpu的用户态,这种状态意味着只能执行cpu所有的指令的一小部分(或者称为所有指令的一个子集),这一小部分指令对计算机的硬件资源没有访问权限(比如I/O),并且不能控制由用户态转成内核态.