- 1、进程理论
- 1.1、程序和进程
- 1.2、串行、并发、并行
- 1.3、进程的创建
- 1.4、进程的终止
- 1.5、进程运行的三种状态
- 1.5.1、就绪态
- 1.5.2、运行态
- 1.5.3、阻塞态
- 1.6、优化程序效率的核心法则
- 1.7、同步和异步
- 1.8、阻塞非阻塞
- 2、进程
- 2.1、multiprocessing模块
- 2.2、Process类
- 2.2.1、创建进程的类
- 2.2.2、参数
- 2.2.3、方法
- 2.2.4、属性
- 2.3、Process类的使用
- 2.4、开启进程的两种方式
- 2.4.1、方式一
- 2.4.2、方式二
- 2.5、进程间数据相互隔离
- 2.6、进程调度
- 2.7、僵尸进程和孤儿进程
- 2.8、进程对象及其他方法
- 2.9、守护进程
1、程序 程序就是一堆代码文件,计算机中安装的应用程序在没有打开/运行之前,称之为程序,他是存在于计算机硬盘之上的,换而言之,程序是“死的” 2、进程(进程是操作系统最核心的概念) 计算机中运行的应用程序在打开/运行之后,称之为进程,顾名思义,进程即正在执行的一个过程,换而言之,程序是“活的”,进程是对正在运行程序的一个抽象。1.2、串行、并发、并行
串行: 一个运行完毕再运行下一个 并行: 多个进程是真正意义上一起运行 并发: 看起来是同时运行的,本质还是一个个的运行 进程彼此之间的内存空间隔离,而且是物理隔离 并行肯定属于并发 单核计算机肯定不能实现并行,但是可以实现并发1.3、进程的创建
windows: CreateProcess linux: fork1.4、进程的终止
1. 正常退出(自愿,如用户点击交互式页面的叉号,或程序执行完毕调用发起系统调用正常退出,在linux中用exit,在windows中用ExitProcess) 2. 出错退出(自愿,python a.py中a.py不存在) 3. 严重错误(非自愿,执行非法指令,如引用不存在的内存,1/0等,可以捕捉异常,try...except...) 4. 被其他进程杀死(非自愿,如kill -9)1.5、进程运行的三种状态 1.5.1、就绪态
进程已获得除CPU外的所有必要资源,只等待CPU时的状态。一个系统会将多个处于就绪状态的进程排成一个就绪队列1.5.2、运行态
进程已获CPU,正在执行。单处理机系统中,处于执行状态的进程只有一个;多处理机系统中,有多个处于执行状态的进程1.5.3、阻塞态
正在执行的进程由于某种原因而暂时无法继续执行,便放弃处理机而处于暂停状态,即进程执行受阻(这种状态又称等待状态或封锁状态) ps: 通常导致进程阻塞的典型事件有: 请求I/O,申请缓冲空间等。 一般,将处于阻塞状态的进程排成一个队列,有的系统还根据阻塞原因不同把这些阻塞集成排成多个队列。1.6、优化程序效率的核心法则
降低IO操作(硬盘IO、网络IO) 优化方案: 内存 => 本地硬盘 => 网络IO1.7、同步和异步
描述的是任务的提交方式
同步: 任务提交之后,原地等待任务的返回结果,等待的过程中不做任何事(干等)
程序层面上表现出来的感觉就是卡住了
异步: 任务提交之后,不原地等待任务的返回结果,直接去做其他事情
我提交的任务结果如何获取?
任务的返回结果会有一个异步回调机制自动处理
1.8、阻塞非阻塞
描述的程序的运行状态 阻塞: 阻塞态 非阻塞: 就绪态、运行态 理想状态: 我们应该让我们的写的代码永远处于就绪态和运行态之间切换
总结: 最高效的一种组合就是异步非阻塞
2、进程 2.1、multiprocessing模块python中的多线程无法利用CPU资源,在python中大部分情况使用多进程。python中提供了非常好的多进程包multiprocessing multiprocessing模块用来开启子进程,并在子进程中执行功能(函数),该模块与多线程模块threading的编程接口类似 multiprocessing的功能众多:支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件2.2、Process类 2.2.1、创建进程的类
Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动) 强调: 1. 需要使用关键字的方式来指定参数 2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号2.2.2、参数
group参数未使用,值始终为None
target表示调用对象,即子进程要执行的任务
args表示调用对象的位置参数元组,args=(1,2,'allen',)
kwargs表示调用对象的字典,kwargs={'name':'allen','age':18}
name表示子进程的名称
2.2.3、方法
p.start(): 启动进程,并调用该子进程中的p.run()
p.run(): 进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法
p.terminate(): 强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
p.is_alive(): 如果p仍然运行,返回True
p.join([timeout]): 主线程等待p终止(强调: 是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
2.2.4、属性
p.daemon: 默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置 p.name: 进程的名称 p.pid: 进程的pid p.exitcode: 进程在运行时为None、如果为–N,表示被信号N结束 p.authkey: 进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功2.3、Process类的使用
一定要把开进程的代码写在if __name__=='__main__'下面 开一个进程和主进程是并发的关系,我start一下就是先告诉操作系统我要开一个进程 ,然而它不会等待,它会直接去执行下面的代码,然后就开始执行子进程 strat(): 方法的功能 1.开启进程 2.执行功能2.4、开启进程的两种方式 2.4.1、方式一
from multiprocessing import Process
import time
def task(n, name):
print('{} is running'.format(name))
time.sleep(n)
print('{} is done'.format(name))
if __name__ == '__main__':
obj1 = Process(target=task, args=(3, '进程1'))
obj2 = Process(target=task, args=(5, '进程2'))
obj1.start()
obj2.start()
obj1.join() # 等待子进程obj1执行完成
obj2.join() # 等待子进程obj2执行完成
print('主')
2.4.2、方式二
from multiprocessing import Process
import time
class Mytask(Process):
def __init__(self, n, name):
super().__init__()
self.n = n
self.name = name
def run(self) -> None:
print('{} is running'.format(self.name))
time.sleep(self.n)
print('{} is done'.format(self.name))
if __name__ == '__main__':
obj1 = Mytask(3, '进程1')
obj2 = Mytask(5, '进程2')
obj1.start()
obj2.start()
obj1.join()
obj2.join()
print('主')
2.5、进程间数据相互隔离
from multiprocessing import Process
import time
number = 10
def task(n):
global number # 局部修改全局
number = 20
time.sleep(n)
print('子进程中number的值为: {}'.format(number)) # 20
if __name__ == '__main__':
t = Process(target=task, kwargs={'n': 1})
t.start()
t.join() # 等待t子进程执行完成
print('主进程中number的值为: {}'.format(number)) # 数据没有变,主进程中打印age和子进程的age没有关系,数据是隔离的,结果还是10
2.6、进程调度
1、先来先服务 2、短作业优先 3、时间片轮转 4、多级反馈队列2.7、僵尸进程和孤儿进程
1、僵尸进程: 进程结束了,资源还没来得及回收 2、孤儿进程: 主进程挂了,子进程还没结束,它就会被专门的进程接管2.8、进程对象及其他方法
from multiprocessing import Process, current_process
import os
import time
def task():
print('子进程')
print('task函数内子进程id: {}'.format(os.getpid()))
print('task函数内子进程id: {}'.format(current_process().pid))
print('task函数内子进程的父进程id: {}'.format(os.getppid()))
print('task函数内: {}'.format(current_process().is_alive()))
time.sleep(2)
print('子进程结束')
if __name__ == '__main__':
t = Process(target=task)
t.start()
t.join()
t.terminate()
time.sleep(0.1)
print(t.is_alive())
print('子进程id: {}'.format(t.pid))
print('主进程id: {}'.format(os.getpid()))
总结:
1、windows:tasklist |findstr 进程id号
2、mac,Linux:ps aux | grep 进程id号
3、进程对象: t=Process(target=task)或者是在进程内部: current_process()
4、t.pid或者current_process().pid # 获取进程id号
5、os.getpid() # 同上,获取进程id号
6、os.getppid() # 获取父进程id号,子进程中获取父进程id,等于父进程的id号
7、t.is_alive()或者current_process().is_alive() # 查看进程是否存活
8、t.terminate() # 关闭进程,在主进程关闭
2.9、守护进程
守护进程: 主进程一旦结束,子进程也结束
from multiprocessing import Process
import time
def task():
print('子进程开始')
time.sleep(2)
print('子进程结束')
if __name__ == '__main__':
t = Process(target=task)
t.daemon = True # 一定要加在启动之前
t.start()
print('主进程结束')
问题1: 主进程的父进程是谁?
如果是用pycharm运行的代码主进程的父进程就是pycharm
问题2: 主进程开了很多子进程,每个都需要设置守护吗?
主要还是看你的需求,你想让某个进程是守护,就设置t.daemon=True



