1. 多进程
程序:program是一个指令的集合
进程:process,正在执行中的程序,是一个静态的概念
1) 进程是程序的一次静态执行过程,占用特定的地址空间
2) 每个进程都是独立的,由3部分组成cpu,data,code
3) 缺点:内存的浪费,cpu的负担
4) 数据区、代码区、堆、栈
操作系统轮流让各个任务交替执行,由于CPU的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样
真正的并行执行多任务只能在多核心CPU上实现,但是,由于任务数据远远多于CPU的核心数量,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行
在unix/linux操作系统中,提供了一个fork()系统函数,它非常特殊
1) 普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回
2) 子进程永远返回0,而父进程返回子进程的ID
3) 一个父进程可以fork出很多子进程,所以,父进程要记下每个子进程 的ID,而子进程中需要调用getppid()就可以拿到父进程的id
4) 父进程、子进程执行顺序没有规律,完全取决于操作系统的调度算法
进程拥有独立的运行空间,变量的值不能共享
由于python是跨平台的,自然也应该提供一个跨平台的多进程支持。multiprocessing模块就是跨平台版本的多进程模块
multiprocessing模块提供了一个process类来代表一个进程对象
创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()方法启动,这样创建进程比fork()还要简单
Process([group [,target [,name [,args [,kwargs]]]]])
target | 表示这个进程实例所调用对象 |
args | 表示调用对象的位置参数,元组 |
kwargs | 表示调用对象的关键字参数,字典 |
name | 为当前进程实例的别名 |
group | 创建一个进程组,大多数情况下用不到 |
Process类常用方法 |
join()方法 | 可以等待子进程结束后再继续往下运行,通常用于进程间的同步 |
is_alive() | 判断进程实例是否还在执行 |
join([timeout]) | 是否等待进程实例执行结束,或等待多少秒 |
start() | 启动进程实例(创建子进程) |
run() | 如果没有给定target参数,对这个对象调用start()方法时,就将执行对象中的run()方法 |
terminate() | 不管任务是否完成,立即终止 |
Process类常用属性 |
name | 当前进程实例别名,默认为Process-N,N为从1开始递增的整数 |
pid | 当前进程实例的pid值 |
例1
例2
创建新的的进程还能够使用类的方式,可以自定义一个类,继承Process类,每次实例化这个类的的时候,就等同于实例化一个进程对象
例,创建多个进程
multiprocessing的Pool方法
当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态生成多个进程,但如果是上百甚至上千个目标,手动去创建进程进程的工作量巨大,此时就可可以用到到multiprocessing模块提供的Pool方法
初始化Pool时,可以指定一个最大进程数,当有有新的请求提交到Pool时,如果池还没满,那么就会创建一一个新的进程用来执行该请求,但如果池中的进程数已经达到到指定的最大值,那么该请求就会会等待,直到池中有进程结束,才会创建新的进程来执行。
multiprocessing.Pool常用函数解析
apply_async(func[,args[,kwds]]):使用非阻塞阻塞方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程进程),args为传递给func的参数列表,kwds为传递给func的关键字参数参数列表;
apply(func[,args[,kwds]]):使用阻塞方式调用func
close():关闭Pool,使其不再接受新的任务。不是马上关,执行中的任务仍会执行。
terminate():不管任务是否完成,立即终止
join():主进程阻塞,等待子进程的退出,必须在colse或terminate之后使用
例,
| |
异步,非阻塞 | 同步,阻塞 |
消息队列
操作系统提供了很多机制来实现进程间的通信 ,multiprocessing模块就提供了Queue和Pipe两种方法来实现
Queue模块专门实现消息队列Queue对象。
queue只有maxsize一个构造参数,用来指定队列容量,指定为0的时候代表容量无限。
主要有以下成员函数:
Queue.qsize():返回消息队列的当前空间。返回的值不一定可靠。
Queue.empty():判断消息队列是否为空,返回True或False。同样不可靠。
Queue.full():类似上边,判断消息队列是否满
Queue.put(item, block=True, timeout=None):往消息队列中存放消息。block可以控制是否阻塞,timeout指定阻塞时候的等待时间。如果不阻塞或者超时,会引起一个full exception。
Queue.put_nowait(item):相当于put(item, False).Queue.get(block=True, timeout=None):获取一个消息,其他同put。