并发编程-进程(多道技术)
并发编程
并发与串行
-
什么是串行?
串行就是程序自上而下,按顺序一行行执行程序,且必须把当前任务执行完毕才能执行下一个程序
问题:
- 程序执行效率变低
- 占用内存资源
-
什么是并发?
并发就是可以同时执行多个程序(本质是在不同的进程间快速切换执行,并保存程序状态) 总结就是:切换+保存
串行和并发都是程序处理任务的方式
为什么要用并发?
- 可以同时执行多个程序,提高了工作效率
- 提高内存资源的利用率
实现并发的方式
- 多进程
- 多线程
- 协程
什么是进程?
进程指的是正在运行的程序,是操作系统调度以及进行资源分配的基本单位 (进程就是一个资源单位)
-
进程是怎么来的?
当把一个程序从硬盘读入内存时,进程就产生了
-
什么是多进程?
同一时间有多个程序被读入到内存并执行,就是多进程
进程来自于操作系统,有操作系统进行调度以及资源分配
多进程的实现原理其实就是操作系统调度进程的原理
多道技术 (重点)
实现原理:
-
空间复用:
将内存划分多个区域,放入多个程序到内存中,且内存区域相互隔离(物理层面的隔离,为了保证数据安全)
-
时间复用:(切换+保存)
指的是操作系统会在多个进程之间做切换执行
切换任务的两种情况:
- 当一个进程遇到了IO操作时会自动切换
- 当一个任务执行时间超过阈值会强制切换
在切换前必须保存状态,以便后续恢复执行
并发编程中的重要概念(重点)
-
串行:程序自上而下,按顺序一个个执行
-
并发:在不同的人物之间快速切换
-
并行:真正的同时执行多个程序,需要多核CPU
三者都是处理任务的方式
-
阻塞: 指的是程序遇到了IO操作,无法继续执行代码时的一种状态
-
非阻塞:指的是程序没有遇到IO操作的一种状态
-
进程的三种状态
- 阻塞:释放IO操作,转换成就绪
- 运行:遇到IO操作和运行超时,转换成阻塞;释放IO操作转换成就绪
- 就绪:CPU调用,转换成运行
python中使用多进程的两种方式:
-
导入 multiprocessing 中的Process类,实例化这个类,指定要执行的任务程序target
import os from multiprocessing import Process """ Process 就表示进程 为什么要开进程 """ def task(): print("this is sub process") print("sub process id %s" % os.getpid()) if __name__ == '__main__': # ######注意 开启进程的代码必须放在 ————main————判断下面 # 实例化一个进程对象 并制定他要做的事情 用函数来指定 p = Process(target=task) p.start() # 给操作系统发送消息 让它开启进程 print("this is parent process") print("parent process is: %s" % os.getpid()) print("over")
-
导入 multiprocess 中的Process类,继承这个类,覆盖run方法,将要执行的任务放入到run中开启进程是会自动执行该函数
from multiprocessing import Process import os class Downloader(Process): # def __init__(self,url,size,name): # super().__init__() # self.url = url # self.size = size # self.name = name def run(self): print(os.getpid()) pass if __name__ == '__main__': m = Downloader() m.start() print("parent over",os.getpid())
join函数(重点)
主要能提高子进程的优先级,使得子进程执行完成后,在执行父进程
from multiprocessing import Process
import time
def task1(name):
for i in range(10000):
print("%s run" % name)
def task2(name):
for i in range(100):
print("%s run" % name)
if __name__ == '__main__': # args 是给子进程传递的参数 必须是元组
p1 = Process(target=task1,args=("p1",))
p1.start() # 向操作系统发送指令
# p1.join() # 让主进程 等待子进程执行完毕在继续执行
p2 = Process(target=task2,args=("p2",))
p2.start() # 向操作系统发送指令
p2.join() # 让主进程 等待子进程执行完毕在继续执行
p1.join()
#需要达到的效果是 必须保证两个子进程是并发执行的 并且 over一定是在所有任务执行完毕后执行
print("over")
进程对象的常用属性 (了解)
# p.daemon #守护进程
# p.join()
# print(p.exitcode) # 获取进程的退出码 就是exit()函数中传入的值
# print(p.is_alive()) # 查看进程是否存活
# print("zi",p.pid) # 获取进程id
# print(os.getpid()) #获取当前进程的编号
# p.terminate() #终止进程 与strat 相同的是 不会立即终止,因为操作系统有很多事情要做
# print(p.is_alive()) 判断进程是否存活
僵尸进程和孤儿进程
孤儿进程 当父进程已经结束 而子进程还在运行 子进程就称为孤儿进程 尤其存在的必要性,没有不良影响
僵尸进程 当一个进程已经结束了但是,它仍然还有一些数据存在 此时称之为僵尸进程
在linux中,有这么一个机制,父进程无论什么时候都可以获取到子进程的的 一些数据
子进程 任务执行完毕后,确实结束了但是仍然保留一些数据 目的是为了让父进程能够获取这些信息
linux中 可以调用waitpid来是彻底清除子进程的残留信息
python中 已经封装了处理僵尸进程的操作 ,无需关心