【操作系统发展史】
1 为什么要使用操作系统呢? 2 程序员无法把所有的硬件操作细节都了解到,管理这些硬件并且加以优化使用是非常繁琐的工作, 3 这个繁琐的工作就是操作系统来干的,有了他,程序员就从这些繁琐的工作中解脱了出来, 4 只需要考虑自己的应用软件的编写就可以了,应用软件直接使用操作系统提供的功能来间接使用硬件。 5 6 -------------- 7 8 操作系统的两大作用 9 1.为应用程序提供如何使用硬件资源的抽象 10 2.把多个程序对硬件的竞争变得有序化(管理应用程序) 11 12 13 --------------- 14 计算机中真正干活的是CPU 15 --------------------------------------------- 16 17 1.穿孔卡片阶段 18 计算机很庞大 使用很麻烦 一次只能给一个人使用 期间很多时候计算机都不工作 19 好处:程序员独占计算机 为所欲为 20 坏处:计算机利用率太低 浪费资源 21 出现人机矛盾:手工操作的慢速度和计算机的高速度之间形成了尖锐矛盾,手工操作方式已严重损害了系统资源的利用率(使资源利用率降为百分之几,甚至更低),不能容忍。唯一的解决办法:只有摆脱人的手工操作,实现作业的自动过渡。这样就出现了成批处理。 22 ---------------------------------------------- 23 24 批处理系统:加载在计算机上的一个系统软件,在它的控制下,计算机能够自动地、成批地处理一个或多个用户的作业(这作业包括程序、数据和命令)。 25 首先出现的是联机批处理系统,即作业的输入/输出由CPU来处理。 26 ---------------------------------------------- 27 28 2.联机批处理系统 29 提前使用磁带一次性录入多个程序员编写的程序,然后交给计算机执行 30 CPU工作效率有所提升 不用反复等待程序录入 31 ---------------------------------------------- 32 33 为克服与缓解:高速主机与慢速外设的矛盾,提高CPU的利用率,又引入了脱机批处理系统,即输入/输出脱离主机控制。 34 这种方式的显著特征是:增加一台不与主机直接相连而专门用于与输入/输出设备打交道的卫星机。这样,主机不是直接与慢速的输入/输出设备打交道,而是与速度相对较快的磁带机发生关系,有效缓解了主机与设备的矛盾。主机与卫星机可并行工作,二者分工明确,可以充分发挥主机的高速计算能力。 35 3.脱机批处理系统 36 极大地提升了CPU的利用率 37 总结:CPU提升利用率的过程 38 39 ----------------------------
========================================================================================================
脱机批处理系统:它极大缓解了人机矛盾及主机与外设的矛盾。
不足:每次主机内存中仅存放一道作业,每当它运行期间发出输入/输出(I/O)请求后,
高速的CPU便处于等待低速的I/O完成状态,致使CPU空闲。
为改善CPU的利用率,又引入了多道程序系统。
。
。
【多道技术】
1 在学习并发编程的过程中 不做刻意提醒的情况下 默认一台计算机就一个CPU(只有一个干活的人) 2 ---------------------------------------------------- 3 多道技术:(指的是多道/个程序) 4 1.空间上的复用:内存要支持同时跑进多个程序 5 2.时间上的复用:多个程序要让它们能切换(什么时候要切?一个程序占用的时间过长要切;当CPU遇到IO阻塞时,等待的时间要切) 6 ---------------------------------------------------- 7 单道技术 8 所有的程序排队执行 过程中不能重合 9 多道技术 10 利用空闲时间提前准备其他数据 最大化提升CPU利用率 11 -------------------------------------------------- 12 多道技术详细 13 1.切换 14 计算机的CPU在两种情况下会切换(不让你用 给别人用) 15 1.程序有IO操作 16 输入\输出操作 17 input、time.sleep、read、write 18 2.程序长时间占用CPU 19 我们得雨露均沾 让多个程序都能被CPU运行一下 20 -------------------------------------------------- 21 2.保存状态 22 CPU每次切换走之前都需要保存当前操作的状态 下次切换回来基于上次的进度继续执行 23 -------------------------------------------------- 24 开了一家饭店 只有一个服务员 但是同时来了五桌客人 25 请问:如何让五桌客人都感觉到服务员在服务他们 26 让服务员化身为闪电侠 只要客人有停顿 就立刻切换到其他桌 如此往复 27 -------------------------------------------------- 28 程序的I/O操作: 29 I:就是input 、O:就是output ;称为:输入输出流。 30 IO操作,就是将数据写入内存或从内存输出的过程,也指应用程序和外部设备之间的数据传递,常见的外部设备包括文件、管道、网络连接。 31 常见IO操作,一般指内存与磁盘间的输入输出流操作。
。
。
【进程理论】
1 进程与程序的区别 2 程序:一堆死代码(还没有被运行起来) 3 进程:正在运行的程序!!!!!! 4 ------------------------------------- 5 进程的调度算法(重要) 6 1.FCFS(先来先服务) 7 对短作业不友好 8 ------------------------------------- 9 2.短作业优先调度 10 对长作业不友好 11 ------------------------------------- 12 3.时间片轮转法+多级反馈队列(目前还在用)!!!!!!!!!! 13 将时间均分 然后根据进程时间长短再分多个等级 14 等级越靠下表示耗时越长 每次分到的时间越多 但是优先级越低 15 -------------------------------------
PS补充知识点:
(进程调度)
.1 先来先服务(FCFS):对长作业有利,对短作业无益
.2 短作业优先(SJF):对短作业有利,对长作业无益
.3 时间片轮转(RR)+多级反馈队列(Multilevel Feedback Queue):对短作业有利,对长作业有利
。
。
【进程的三状态】
1 运行一个程序首先要双击一下,就表示提交了一个任务,被双击的程序会先进入一个就绪态!! 2 告诉cpu它已经准备好了!!利用cpu的进程调度算法,拿到一个时间片,到了这个时间片, 3 cpu就会执行该程序了,就会进入运行态了,当程序处于运行态后,当在时间片内,该程序已经跑完了,就 4 正常退出运行,释放内存空间。如果在时间片内程序仍然没有运行完也没有I/O操作,那就再次返回就绪态, 5 如果有I/O操作就会进入阻塞态!!cpu会立刻离开该程序,并保存当前的操作状态!! 6 当I/O操作执行结束后,该程序才会从阻塞态转为就绪态并排队!!! 7 8 ---------------------------------------------- 9 10 就绪态 11 所有的进程在被CPU执行之前都必须先进入就绪态等待 12 运行态 13 CPU正在执行 14 阻塞态 15 进程运行过程中出现了IO操作,阻塞态无法直接进入运行态,需要先进入就绪态排队才能变成运行态 16 17 ------------- 18 19 也就是如果让程序尽可能多的在运行态与就绪态来回切回,那么该程序的cpu的利用率就比较高了 20 .
。
。
【同步与异步/阻塞与非阻塞】
(同步与异步:(描述的是任务的提交方式))
1 同步:提交完任务之后原地等待任务的返回结果,期间不做任何事 2 ---------------------------- 3 异步:提交完任务之后不愿地等待任务的返回结果,直接去做其他事,有结果自动通知 4 -------- 5 比如代码运行到某一行,如果这一行代码需要调用其他的代码。 6 同步就是:跑到要调用的代码处执行完后,再回来继续往下。 7 异步就是:运行到调用其他代码的时候,立马往下执行,不会等待要调用的代码走完才往下执行。 8 ----------------------------------- 9 所谓同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,该任务才能算完成,这是一种可靠的任务序列 10 ------------- 11 所谓异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了 12 ------------- 13 去银行办业务 14 第一种:排队等候:就是同步等待消息通知,也就是我要一直在等待银行办理业务情况; 15 16 第二种:取票等待:等待银行人叫号,就是异步等待消息通知。在异步消息处理中,等待办理业务的人往往有一个回调机制,在所等待的事件被触发时由触发机制(在这里是柜台的人)通过某种机制(在这里是写在小纸条上的号码,喊号)找到等待该事件的人。
(阻塞与非阻塞:(描述的是程序的运行状态))
1 阻塞:进程在执行过程中,由于等待一个事件(比如I/O),处于挂起状态,这时进程是阻塞的。 2 非阻塞:进程在执行过程中,如果遇到一个事件(比如I/O),采取通知的方式让进程知道某个事件已经发生,可以继续执行
综合使用
1 同步阻塞: 提交完一个任务后原地等待什么事也做不了,cpu也走了,且程序处于一个阻塞态!!! 2 比如:在银行排队半业务,就站那等,其他什么事也不做!! 3 4 ----------------------- 5 6 同步非阻塞: 比如,提交完一个任务后原地等待,但是可以在原地做一些事情,比如打电话等。没有被阻塞在等待的操作上,但是还只能站在那排队 7 8 ----------------------- 9 10 异步阻塞: 如果在银行等待办理业务的人采用的是异步的方式去等待消息被触发(通知), 11 也就是领了一张小纸条,假如在这段时间里他不能离开银行做其它的事情, 12 那么很显然,这个人被阻塞在了这个等待的操作上面; 13 14 ------------------------ 15 16 异步非阻塞(******) 效率最高!!!没有任何的停顿,立刻就可以做其他事 17 提交完一个任务后,不等待,直接去做其他事,并且整个程序不处于非阻塞态!!! 18 比如你突然发觉自己烟瘾犯了,需要出去抽根烟,于是他告诉大堂经理说, 19 排到我这个号码的时候麻烦到外面通知我一下,那么他就没有被阻塞在这个等待的操作上面, 20 自然这个就是异步+非阻塞的方式了。 21 22 ------------------------- 23 不论是排队还是使用号码等待通知,如果在这个等待的过程中, 24 等待者除了等待消息通知之外不能做其它的事情,那么该机制就是阻塞的, 25 表现在程序中,也就是该程序一直阻塞在该函数调用处不能继续往下执行。
。
。
【开启进程的两种方式】
1.鼠标双击软件图标 2.python代码创建进程 ---------------------------------------------------- 在不同的操作系统中创建新的进程底层原理不一样!!!!!! windows 以导入模块的形式创建进程!!! ---------------------------------------------------- 当加了一行创建新的进程的代码后,会以导入模块的形式, 从上往下再执行一次该py文件里面的代码!!! 然后把执行之后的代码产生的结果,也放到一个新的内存空间里面去!!! python在导模块的时候,只要程序不结束,已经导过的模块就不用再导了!! 所以就直接从导入模块的语句下面开始执行代码了!! 如果创建新的进程的代码,在普通代码的下面,就会出现代码一直反复执行循环的问题, 导致windows频繁的创建进程!!!就会自动报错了!!! ----------------------------------------------------- 如何解决?利用下列语句: if __name__ == '__main__': ----------------------------------------------------- 在该语句下面的代码,只有是在执行文件的时候才会执行!! 所以把创建新的进程的代码发在该语句下面,就可以避免反复执行的问题了!!! 因为第一次创建新的进程的代码可以正常执行,但是windows是以导入模块的形式创建进程的, 所以第二次重上往下执行代码的时候,是以模块的形式执行代码的, 所以走到if __name__ == '__main__': 时就走不了了!!! ---------------------------------------------------- linux/mac 以拷贝代码的形式,创建新的进程的代码,上面的所有代码复制一份,创建进程的代码不复制!! 然后创建一个新的进程,所以不会像windows一样报错!!!!!!
(代码演示)
1 方式一: 2 3 from multiprocessing import Process 4 import time 5 6 7 def task(name): 8 print('%s is running' % name) 9 time.sleep(2) 10 print('%s is over' % name) 11 12 13 # 第一种:函数的调用 14 if __name__ == '__main__': 15 # 1.创建一个对象 16 # process是一个类,target:目标,接下来要把task函数交给p两个进程去执行 17 # 容器类型:哪怕里面只有1个元素,建议一定要用逗号隔开 18 p = Process(target=task, args=('jason',)) 19 # 2.启动进程 20 p.start() # 告诉操作系统帮你创建一个进程,异步 21 print('主进程') 22 ''' 23 window操作系统下,创建进程一定要在main内创建 24 因为window下创建进程类似于模块导入的方式,会从上而下依次执行代码 25 Linux操作系统下,创建进程可以不在main内创建,因为linux下创建进程是将代码完整的拷贝一份 26 ''' 27 28 29 ================================================ 30 方式二: 31 32 from multiprocessing import Process 33 import time 34 35 36 # 类的继承 37 class MyProcess(Process): 38 # 必须定义run 39 def run(self): 40 print('hello bf girl') 41 time.sleep(2) 42 print('get out') 43 44 45 if __name__ == '__main__': 46 p = MyProcess() 47 p.start() 48 print('主进程') 49 50 总结 51 创建进程就是在内存中申请一个内存空间,将需要运行的代码丢进去,一个进程对应在内存中就是一块独立的内存空间, 52 多个进程对应在内存中就是多块独立的内存空间 53 进程与进程之间数据默认情况下是无法直接交互,如果像交互可以借助于第三方模块工具
。
。
【jion方法:是让主进程的代码等待子进程代码运行结束以后再继续运行】
1 from multiprocessing import Process 2 import time 3 4 5 def task(name): 6 print('%s is running' % name) 7 time.sleep(3) 8 print('%s is over' % name) 9 10 11 if __name__ == '__main__': 12 p = Process(target=task, args=('jh',)) 13 p.start() 14 p.join() # 等待p进程执行完毕后,再执行主进程,无论子进程需要多长时间,主进程都要最后执行 15 print('主进程') 16 17 18 ================================================= 19 多道技术,迷惑性题目 20 21 from multiprocessing import Process 22 import time 23 24 25 def task(name,n): 26 print('%s is running' % name) 27 time.sleep(n) 28 print('%s is over' % name) 29 30 31 if __name__ == '__main__': 32 p = Process(target=task, args=('jh',1)) 33 p2 = Process(target=task, args=('wxx',2)) 34 p3 = Process(target=task, args=('yxx',3)) 35 start_time = time.time() 36 p.start() 37 p2.start() 38 p3.start() # 仅仅是告诉操作系统要创建进程,谁先启动不一定,随机 39 p.join() 40 p2.join() 41 p3.join() # 这时候是多道,运行时间总共才3秒多 42 print('主进程', time.time() - start_time)
。
。
【进程间数据隔离】
同一台计算机上的多个进程数据是严格意义上的物理隔离(默认情况下不能交互的)!!!
注意一个进程就是一个内存空间
1 from multiprocessing import Process 2 3 money = 1000 4 5 6 def task(): 7 global money # 局部修改全局 8 money = 100 9 10 11 if __name__ == '__main__': 12 p = Process(target=task) 13 p.start() 14 print(money) # 打印输出是1000, global没有改变全局
1 # 验证进程间数据隔离 2 from multiprocessing import Process 3 import time 4 money = 1000 5 6 7 def task(): 8 global money # 局部修改全局 9 money = 100 10 print('子进程下的money') # 要打印一下: 输出100,验证进程间数据隔离 11 12 13 if __name__ == '__main__': 14 p = Process(target=task) 15 p.start() 16 time.sleep(3) # # 主进程代码等待3秒,等待3秒的过程中,子进程代码肯定运行完了! 17 # p.join() 18 print(money) # # 主进程代码打印money 结果还是1000 19 20 当右键运行py文件的时候,立刻会创建该py文件的主进程,创建一个名称空间!!! 21 该名称空间里面先定义 money=1000 再定义一个task函数但是没有调用!!! 22 23 当走到p1.start()时,会创建一个新的进程,又会创建一个新的名称空间!! 24 以导模块的形式,代码又从上往下走一遍!!在新的内存空间里面又会定义一个 money=1000 25 再定义一个task函数 26 并且运行task函数,此时task函数里面改的是子进程里面的全局的money!!! 27 和主进程里面的全局money没关系!!!