由于Python的GIL全局解释器锁的存在,多进程未必是CPU密集型程序最好的选择。
多进程可以完全独立的进程环境中运行程序,可以比较充分的利用多处理器。
但是进程本身的隔离带来的数据不共享也是一个问题,而且线程比进程轻量级。
multiprocessing
process类
名称 | 说明 |
---|---|
pid | 进程id |
exitcode | 进程的退出状态码 |
terminate() | 终止指定的进程 |
进程间同步
Python在进程间同步提供了和线程同步一样的类,使用方法一样,使用的效果也类似。
不过,进程间代价要高于线程间,而且系统底层实现是不同的,只不过Python屏蔽了这些不同。
通信方式不同:
1、多进程就是启动多个解释器进程,进程间通信必须序列化、反序列化。
2、数据的线程安全性问题,如果每个进程中没有实现多线程,也就没有GIL
进程池
multiprocessing.Pool是进程池类
名称 | 说明 |
---|---|
apply(self,func,args=(),kwds={}) | 阻塞执行,导致主进程执行其他子进程就行一个个执行 |
apply_async(self,func,args=(),kwds={},callback=None,error_callback=None) | 与apply用法一致,非阻塞异步执行,得到结果会执行huid |
close() | 关闭池,池不接受新的任务,所有任务完成后退出进程 |
terminate() | 立即结束工作进程,不再处理未处理的任务 |
join() | 主进程阻塞等待子进程的退出,join方法要在close或terminate之后使用 |
多进程、多线程的选择
1、CPU密集型
CPython中使用了GIL,多线程的时候锁相互竞争,且多核优势不能发挥出来,选用Python多进程效率更高。
2、IO密集型
在Python中适合多线程,可以减少多进程间IO的序列化开销,且在IO等待的时候,切换到其他线程继续执行。
Linux的特殊进程
在Linux中,通过父进程创建子进程
- 僵尸进程
一个进程使用了fork创建了子进程,如果子进程终止进入了僵死状态,而父进程并没有调用wait或者waitpid获取子进程的状态信息,那么子进程仍留下一个数据结果保存在系统中,这种进程成为僵尸进程。
僵尸进程会占用一定的内存空间,还占用了进程号,所以一定要避免大量的僵尸进程的产生。 - 孤儿进程
父进程退出,子进程仍在运行,那么这些子进程就会成为孤儿进程。 - 守护进程
它是运行在后台的一种特殊进程。它独立于控制中毒那并周期性执行某种任务或等待处理某些事件。