day 28 操作系统,进程
01.操作系统的发展史
-
穿孔卡片
- 一个计算机,一次只能被一个卡片使用,当这个卡片(程序)运行结束后才可以读取下一张卡片的内容
- 缺点;CPU利用率低
-
联机批处理
- 主机与输入机之间增加一个存储设备——磁带,
- 加载在计算机上的一个系统软件,在他的控制计算机可以自动在上一个程序结束后读取下一个卡片的内容
- 支持多个用户去使用一个计算机
-
脱机批处理
- 在输入机、主机、输出机之外在添加一台卫星机,
- 使高速主机与高速磁带机进行交互,不直接与慢速的输入输出机交互
- 优点;高速磁盘提高了文件的读取速度,提高了CPU的利用率
- 缺点;在程序进入IO(与用户交互)阶段时,CPU处于等待状态
-
多道技术(基于单核)
-
单道;
- 多个程序使用CPU时按照先后顺序串式运行,当前一个程序运行完之后再运行下一个程序
- 缺点;在程序进入IO(与用户交互)阶段时,CPU处于等待状态
-
多道;
- 指允许多个程序同时进入内存并运行,允许它们在CPU中交替运行,共享计算机中的各种硬件资源
- 当一道程序进入IO状态时,CPU立即转去运行另一道程序
-
空间隔离、空间复用、时间复用
- 空间隔离;多个程序并存在内存中,内存的空间隔离才能让数据更加安全、稳定
- 空间复用;一个CPU可以提供给多个程序去使用
- 时间复用;遇到IO处理,即将CPU使用移交给另一个程序,同时保存当前状态,在处理结束后立即切换回来
- IO操作;
- input
- time.sleep
- 若CPU遇到IO操作,会立即将当前执行程序CPU使用权断开,CPU利用率高
- 若一个程序使用CPU时间过长,会立即将当前程序CPU使用全段开,程序执行率低
-
-
并发与并行
- 并发;多个程序不停的来回切换+保存状态,看起来像是在同时运行
- 并行;多核CPU,同时进行多个程序的运行,真正的在同时运行
02.进程
- 程序与进程
- 程序;一堆代码
- 进程;一堆代码运行的过程
- 进程调度
- 当代操作系统调度;
- 时间片轮转法+分级反馈队列
- 先来先服务调度
- 两个程序都要运行,先来的先使用CPU
- 缺点;第二个程序必须要等第一个程序使用完CPU才能使用
- 短作业优先调度
- 那个程序用时短,优先使用CPU
- 缺点;有多个程序要运行时,用时最长的那个要等其他所有程序运行结束之后才能使用CPU
- 时间片轮转法
- 让等待CPU执行的每个程序都一次运行固定长度的时间,再到队尾从新排队
- 分级反馈队列
- 将执行程序按照优先级分为不同的梯队
- 赋予各梯队的时间片长度不同,优先级越高的梯队时间片长度越短(更像同时运行)(下一层时间片长度是上层的一倍)
- 当上层梯队全部运行结束时才运行下层梯队,当有高优先级的进程新加入时,该进程抢占当前进程,当前进程保存状态排到队尾
- 当代操作系统调度;
- 进程的三个状态
- 就绪态;所有进程在创建后都会进入该状态,准备调度,该进程已经分配到了除CPU外的所有必要资源
- 运行态;该进程正在处理器上运行
- 阻塞态;正在执行的进程由于等待某个事件(输入输出,暂停)的发生而停止执行时,便放弃处理机会进入阻塞态。
- 同步和异步
- 指的是提交任务的方式
- 同步
- 当一个任务的完成需要依赖另一个任务时,只有当被依赖任务运行结束后,依赖任务才能算完成
- 是一种可靠的任务序列,要么都成功,要么都失败,两个任务的状态保持一致
- 异步
- 当一个任务的完成需要依赖另一个任务时,不需要等待被依赖任务完成工作,依赖的任务也立即执行
- 是一种不可靠的任务序列,只要自己完成就算完成,无法确定被依赖任务是否完成
- 阻塞和非阻塞
- 指程序等待消息时的状态
- 阻塞;程序遇到IO进入阻塞态(等待消息时不做其他运作)
- 非阻塞;程序在就绪态和运行态(等待消息时正常处理其他运作)
- 最大华提高CPU的使用率,尽可能减少不必要的IO操作
03.创建进程的两种方式
-
import time from multiprocessing import Process # 创建子进程的方法 print('主进程开始') time.sleep(0.5) # 定义一个任务 def task(name): print(f'{name}的任务开始执行') time.sleep(1) print(f'{name}的任务已经结束') # 在linux/mac系统下不会报错 # p = Process(target=task, args=('jason',)) if __name__ == '__main__': p = Process(target=task, args=('jason',)) # target=执行函数的地址,args=以元组形式输入函数参数 p.start() # 向操作系统提交创建进程的任务 time.sleep(0.5) print('主进程结束')
-
# 方法二 # 自定义一个类,并继承Process class MyProcess(Process): def run(self): # 父类的方法 # 必须写run方法,且不能给其传参 print('任务开始执行') time.sleep(1) print('任务已经结束') if __name__ == '__main__': p = MyProcess() p.start() print('主进程')
03.进程号回收的两种条件
- join方法;用来告诉操作系统先结束子进程
# 在调用子进程后添加
p.start()
p.join() # 告诉操作系统在子进程p结束后再向下运行主进程
- 主进程正常结束,子进程与主进程号也会被回收
进程间数据是相互隔离的
主进程与子进程会产生各自的名称空间
from multiprocessing import Process
x = 100
def func():
print('执行func函数...')
global x
x = 200
if __name__ == '__main__':
p = Process(target=func)
p.start()
print(x) # x=100
print('主')
04.进程对象的属性
current_process().pid # 获取子进程号
os.getpid() # 获取主进程号
os.getppid() # 获取主进程的主进程号
05.僵尸进程和孤儿进程
- 僵尸进程;指子进程已经结束,但PID号还存在,未被销毁,占用PID号和操作系统资源
- 孤儿进程;指子进程还在执行但主进程意外关闭,操作系统的优化机制,提供一个福利院回收没有主进程的子进程
06.守护进程
指的是主进程结束后,该主进程产生的所有的子进程都跟着结束
from multiprocessing import Process
from multiprocessing import current_process
import time
def task(name):
print(f'{name} start...', current_process().pid)
time.sleep(5)
print(f'{name} over..', current_process().pid)
print(f'管家{name}')
if __name__ == '__main__':
p1 = Process(target=task, args=('jason', ))
# 添加守护进程参数
p1.daemon = True # True代表该进程是守护进程
p1.start()
print(f'egon 驾鹤西去...')