三态:
就绪态:进程具备执行条件,等待执行
运行态:正占用cpu执行
等待态:让出cpu,暂停执行
五态:
新建
终止
状态查看命令:
ps -aux --->STAT列
S:等待态
R:执行态
Z:僵尸
<:有较高优先级
N:优先级较低
+:前台进程
s:会话组组长
l:有多线程的
2、父子进程
1、父子进程拥有独立的空间,各自使用自己的空间资源,子进程会复制父进程的全部内存空间,从fork下一句开始执行 2、父子进程各自独立运行,运行顺序不一定 3、父进程之前开辟的空间子进程同样拥有,父子进程对各自空间的操作不会相互影响 4、父子进程的退出不影响对方继续运行3、孤儿和僵尸
孤儿进程:父进程先于子进程退出,此时子进程成为孤儿进程 孤儿进程会被系统进程收养,此时系统进程就会成为孤儿进程的新的父进程,孤儿进程退出该进程会自动处理(孤儿进程不会成为僵尸进程) 僵尸进程:子进程先于父进程退出,父进程又没有处理子进程的退出状态,此时子进程就会成为僵尸进程 僵尸进程虽然结束,但是会存留部分PCB在内存中,大量的僵尸进程会浪费系统内存资源 如何避免: 1、使用wait函数处理子进程退出: pid, status = os.wait() 功能:阻塞函数,在父进程中阻塞等待子进程退出 返回值:pid 退出的子进程pid;status 子进程退出状态 2、创建2级子进程处理僵尸: 2.1、父进程创建子进程,等待回收子进程 2.2、子进程创建二级子进程然后退出 2.3、二级子进程成为孤儿,和父进程一起执行事件 3、通过信号处理子进程退出: 子进程退出时会发送信号给父进程,如果父进程忽略子进程信号,则系统会自动处理子进程退出 使用signal模块在父进程创建子进程前写如下语句: import signal signal.signal(signal.SIGCHLD, signal.SIG_IGN)4、python实现多进程 4.1、os.fork
说明:只能在linux下调用,Windows内核中无fork函数
相关函数:
pid = os.fork()
功能:创建新进程
返回值:int型
在父进程中:返回子进程的pid;
在子进程中:返回0
创建失败:返回pid < 0;
pid = os.getpid()
返回值:当前进程的pid
pid = os.getppid()
返回值:父进程的pid
sys.exit([status])
功能:退出进程
参数:整数表示退出状态,字符串表示退出时打印的内容
pid, status = os.wait()
功能:阻塞函数,在父进程中阻塞等待子进程退出
示例:
import os
import sys
# -*- coding: utf-8 -*-
import os, sys
from time import sleep
def func1():
for i in range(3):
sleep(2)
print("thing1")
def func2():
for i in range(2):
sleep(4)
print("thing2")
pid = os.fork() # 子进程从fork的下一句开始执行,子进程会copy父进程的全部内存空间
if pid < 0: # pid < 0,创建子进程失败
print("Create process failed")
elif pid == 0: # 返回0,在子进程中,一级子进程
p = os.fork()
if p == 0: # 二级子进程
func1() # 在2级子进程中执行func1
else:
sys.exit(0) # 退出一级子进程,二级子进程成为孤儿进程
else: # 父进程
os.wait() # 阻塞等待一级子进程退出,很快,因为创建完二级子进程一级子进程马上就退出了
func2() # 在父进程中执行func2
"""
思路:
在一级子进程中创建2级子进程,然后马上退出1级子进程,二级子进程成为孤儿进程;
在二级子进程中运行f1(),父进程中等待1级子进程退出(很快,因为创建完二级子进程马上就退出了),
这样就实现了两个进程同时运行(分别在父进程和2级子进程中运行)而不产生僵尸进程
"""
4.2、multiprocessing
from multiprocessing import * Process() 功能:创建进程对象 参数:target绑定要执行的目标函数 args元组:用于给target函数位置传参 kwargs字典:给target函数键值传参 p.start() 功能:启动进程 p.join([timeout]) 功能:阻塞等待回收进程 参数:超时时间 multiprocessing总结: 1、使用multiprocessing创建进程同样是子进程复制父进程的空间代码段,父子进程运行互不影响 2、子进程只运行target绑定的函数部分,其余部分都是父进程执行内容 3、multiprocessing中父进程往往只用来创建子进程和回收子进程,具体事件由子进程完成 4、multiprocessing创建的子进程中无法使用标准输入
示例:
import time
from multiprocessing import *
# -*- coding:utf-8 -*-
"""
创建多个子进程执行任务,父进程只负责开始和回收,不做其他事
"""
from multiprocessing import Process
from time import sleep
import os
def add(a, b):
sleep(3)
print("a + b = %d" % (a + b))
def sub(a, b):
sleep(3)
print("a - b = %d" % (a - b))
if __name__ == "__main__":
funcs = [add, sub]
jobs = []
start = time.time()
for func in funcs:
p = Process(target=func, args=(10,), kwargs={'b':3})
jobs.append(p) # 将进程对象保存,一起回收
p.start() # 注意:不能在start()后直接join(),因为join是阻塞函数。
for i in jobs: #一起回收
i.join()
print(time.time() - start)
运行结果如下:
a + b = 13 a - b = 7 3.151749849319458
每个程序都会sleep 3s,如果单进程执行,则总运行时间会超过6s。
5、进程池进程池原理:
创建一定数量的进程来处理事件,事件处理完成进程不退出,而是继续处理其他事件,直到所有事件全都处理完毕统一销毁。
增加进程的重复利用,降低资源消耗
进程池实现:
1、创建进程池对象,放入适当进程
from multiprocessing import Pool
Pool(processes)
功能:创建进程池对象
参数:指定进程数量,默认根据系统自动判定
2、将事件加入进程池队列执行
pool.apply_async(func, args, kwds)
功能:使用进程池执行func事件
参数:func事件函数
args:元组,给func按位置传参
kwds:字典,给func按键值对传参
3、关闭进程池
pool.close()
4、回收进程池中的进程
pool.join()
示例:
# -*- coding:utf-8 -*-
"""
进程池示例
"""
import time
from multiprocessing import Pool
from time import sleep,ctime
def func01(data):
sleep(5)
print(data)
if __name__ == "__main__":
start = time.time()
#创建进程池
pool = Pool(6)
#向进程池添加事件
for i in range(10):
msg = "test %2d" % i
pool.apply_async(func=func01, args=(msg,))
#关闭进程池
pool.close()
#回收进程池
pool.join()
print(time.time() - start)
运行结果:
test 0 test 1 test 2 test 4 test 3 test 5 test 6 test 7 test 8 test 9 10.3250455856323246、进程间通信 6.1、管道通信
管道通信:
Process--->Pipe--->Process
方法:
from multiprocessing import Pipe
fd1, fd2 = Pipe(duplex = True)
功能:创建管道
参数:默认双向管道
如果是False则是单向管道
返回值:表示管道两端的读写对象
如果是双向管道,则均可读写
如果是单向管道,则fd1只读,fd2只写
fd.recv()
功能:阻塞函数,从管道获取内容
返回值:获取到的数据
fd.send()
功能:向管道写入数据
参数:要写入的数据
注意:
1、multiprocessing中管道通信只能用于有亲缘关系的进程中(父子、兄弟)
2、管道对象在父进程中创建,子进程通过父进程获取
示例:
from multiprocessing import Pipe, Process
def func01(*args):
args[0].send("func01 data to func02")
data = args[0].recv()
print("func01 received: " + data)
def func02(*args):
data = args[0].recv() #阻塞等待读取管道内容
print("func02 received: " + data)
args[0].send("func02 data to func01")
if __name__ == "__main__":
pip1, pip2 = Pipe()
p1 = Process(target=func01, args=(pip1,))
p2 = Process(target=func02, args=(pip2,))
p1.start()
p2.start()
p1.join()
p2.join()
运行结果:
func02 received: func01 data to func02 func01 received: func02 data to func016.2、队列通信
队列通信:(读写队列,先进先出)
方法:
from multiprocessing import Queue
q = Queue(maxsize=0)
功能:创建队列对象
参数:最多存放消息个数
返回值:队列对象
q.put(data,[block,time])
功能:向队列存消息
参数:data:存入的内容
block:设置是否阻塞,False为非阻塞,非阻塞时,对列满了就报错
timeout:检测超时,只有在阻塞时才检测,超过超时时间就报错
q.get([block,time])
功能:从队列取出消息
参数:block:设置是否阻塞
timeout:检测超时
q.full() 判断队列是否为满
q.empty() 判断队列是否为空
q.qsize() 获取队列中消息个数
q.close() 关闭队列
示例:
from multiprocessing import Queue,Process
from time import sleep
from random import sample,randint
def func01(q):
l = [1, 2, 3, 4, 5]
for i in l:
q.put(i)
def func02(q):
while True:
try:
print(q.get(timeout=2))
except Exception as e:
break
if __name__ == "__main__":
q = Queue(5)
p1 = Process(target=func01, args=(q,))
p2 = Process(target=func02, args=(q,))
p1.start()
p2.start()
p1.join()
p2.join()
运行结果:
1 2 3 4 5



