[TOC]
操作系统发展史
穿孔卡片
一个计算机机房,一次只能被一个卡片使用
缺点:CPU利用率最低
联机批处理系统
支持多用户使用一个计算机机房
脱机批处理系统
高速磁盘:提高文件的读取速度
优点:提高CPU的利用率
多道技术(基于单核情况下研究)
单道
多个使用CPU时是串行
多道技术
-
空间上的复用:一个CPU可以提供多个用户去使用
-
时间上的复用:切换+保存状态
-
若CPU遇到IO操作,立即将当前执行程序CPU使用权断开
优点:CPU的利用率高
-
若一个程序使用CPU的时间过长,会立即将当前执行程序CPU使用权断开
缺点:程序的执行率降低
并发和并行
并发:指的是看起来像同时在运行,多个程序不停 切换+保存状态
并行:真正意义上的同时运行,在多核的情况下,同时执行多个程序
进程
程序和进程
程序
一堆代码
进程
一堆代码运行的过程
创建进程的两种方式
# from multiprocessing import Process
# import time
'''
创建进程方式一:
'''
# # 1.定义一个任务
# def task(name):
# print(f'{name}的任务开始执行')
# time.sleep(1)
# print(f'{name}的任务已经结束')
#
#
# # 在linux/mac系统下不会报错
# # p = Process(target=task, args=('jason',))
#
# if __name__ == '__main__':
# # target=执行函数的地址
# p = Process(target=task, args=('jason',))
# # 向操作系统提交创建进程的任务
# p.start()
# print('主进程')
'''
windows:
创建子进程,windows会将当前父进程代码重新加载执行一次。
linux/mac:
会将当前父进程代码重新拷贝一份,再去执行。
# 创建进程方式二:
# 1.自定义一个类,并继承Process
# class MyProcess(Process):
#
# # 父类的方法
# def run(self):
# print('任务开始执行')
# time.sleep(1)
# print('任务已经结束')
#
#
# if __name__ == '__main__':
# p = MyProcess()
# p.start()
# # p.start()
# print('主进程')
'''
join方法: 用来告诉操作系统,让子进程结束后,父进程再结束。
'''
# from multiprocessing import Process
# import time
#
#
# def task(name):
# print(f'{name} start...')
# time.sleep(2)
# print(f'{name} over..')
#
#
# if __name__ == '__main__':
# p = Process(target=task, args=('jason', ))
# p.start() # 告诉操作系统,开启子进程
# p.join() # 告诉操作系统,等子进程结束后,父进程再结束。
# print('主进程')
from multiprocessing import Process
import time
def task(name, n):
print(f'{name} start...')
time.sleep(n)
print(f'{name} over..')
if __name__ == '__main__':
p1 = Process(target=task, args=('jason', 1))
p2 = Process(target=task, args=('egon', 2))
p3 = Process(target=task, args=('sean', 3))
p1.start()
p2.start() # 告诉操作系统,开启子进程
p3.start() # 告诉操作系统,开启子进程
p1.join() # 告诉操作系统,等子进程结束后,父进程再结束。
p2.join()
p3.join()
print('主进程')
'''
进程间数据相互隔离:
主进程与子进程会产生各自的名称空间。
'''
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)
print('主')
'''
current_process().pid: 获取子进程号
os.getpid(): 获取主进程pid号
cmd中查看进程号: tasklist |findstr 进程号
进程号回收的两种条件:
1.join,可以回收子进程与主进程。
2.主进程正常结束,子进程与主进程也会被回收。
os.getppid()
'''
from multiprocessing import Process
from multiprocessing import current_process
import os # 与操作系统交互
import time
def task(name):
print(f'{name} start...', current_process().pid)
time.sleep(1)
print(f'{name} over..', current_process().pid)
if __name__ == '__main__':
p = Process(target=task, args=('jason', ))
p.start() # 告诉操作系统,开启子进程
# 判断子进程是否存活
print(p.is_alive())
# 直接告诉操作系统,终止 子进程
p.terminate()
time.sleep(0.1)
# 判断子进程是否存活
print(p.is_alive())
p.join() # 告诉操作系统,等子进程结束后,父进程再结束。
print('主进程', os.getpid())
print('主主进程', os.getppid())
time.sleep(100)
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 驾鹤西去...')
进程调度
当代操作系统的调度:时间片轮转法+分级反馈队列
- 先来先服务调度:程序a先使用,程序b必须等待程序a使用cpu结束后才能使用
- 短作业优先调度:若程序a使用时间最长,有N个程序使用时间短, 必须等待所有用时短的程序结束后才能使用
- 时间片轮转法:CPU执行的时间1秒中,加载N个程序,要将1秒等分成多N个时间片
- 分级反馈队列:将执行优先分为多层级别
进程的三个状态
就绪态
所有进程创建时都会进入就绪态,准备调度
运行态
调度后的进程,进入运行态
阻塞态
凡是遇到IO操作的进程,都会进入阻塞态。 若IO结束,必须重新进入就绪态
同步和异步
指的是提交任务的方式
同步
若有两个任务需要提交,在提交第一个任务时, 必须等待该任务执行结束后,才能继续提交并执行第二个任务
import time
def test():
# IO操作
# time.sleep(3)
# 计算操作
num = 1
for line in range(1000000000000000000000000):
num += 1
if __name__ == '__main__':
test()
print('hello tank')
#等test函数执行结束,才执行打印
异步
若有两个任务需要提交,在提交第一个任务时,
不需要原地等待,立即可以提交并执行第二个任务
阻塞与非阻塞
阻塞
阻塞态。遇到IO一定会阻塞
非阻塞
就绪态、运行态
进程号回收的两种条件
-
join,可以回收子进程与主进程
-
主进程正常结束,子进程与主进程也会被回收
-
僵尸进程与孤儿进程(了解)
僵尸进程:指的是子进程已经结束,但PID号还存在,未销毁
缺点:占用PID号,占用操作系统资源
孤儿进程:指的是子进程还在执行,但父进程意外结束
操作系统优化机制:提供一个福利院,帮你回收没有父亲的子进程
-
守护进程:指的是主进程结束后,该主进程产生的所有子进程跟着结束,并回收