聊聊 Python 多进程
之前一直没关注过多进程这方面,朋友问起时感觉很奇怪,因为进程是资源分配的最小单元,线程是运算调度的最小单元,代码程序本质上只是一些文本文件,给他分配对应的资源运行起来才是进程,那为什么会有多进程呢?看了看文档发现原来是通过创建子进程并管理来实现多进程。
多进程和多线程有什么区别?
虽然同样是并发,同样是均衡 CPU 与 IO 之间差距过大的运行速率,多线程是多个线程共享一个 CPU,好处是线程间通信或切换很容易,坏处是目前 CPU 都是多核的,很容易出现一核有难八核围观的问题,同时 python 具有 GIL(全局锁),让每个 CPU 在同一时间只能执行一个线程,这让我们很难实现并行计算。而多进程避免了这个问题,同时也要注意,多个进程之间的通信与切换成本更大。
因此 python 的多线程并不适合 CPU 密集型的任务,更适合 IO 密集型的任务
fork vs spawn
fork 速度会更快,因为他是对父进程的整个虚拟内存进行写时复制,包括已经初始化过的 python 解释器,内存中构造的对象,而不需要识别哪些资源是必要的,仅将内存页作为一个整体复制。但这也会带来问题,比如由于 fork 不会复制父进程的线程,如果其他线程持有的存储在内存中的锁也被复制的话,但是因为没有对应的线程进行解锁,就会导致死锁。
spawn 从头开始启动一个 python 子进程,所以安全,不继承父进程的资源,所以也不臃肿,但是启动会较慢。
进程池
进程池 Pool 会帮我们实现简单的多进程任务,我们可以通过 apply() 和 map() 来执行任务并阻塞直到子进程计算完成任务。看下官网代码:
map 可以将可迭代的数据的每一个元素作为一个任务来执行。任务执行结束后可以通过 pool.close()
告诉进程池不再接受新的任务,而 pool.join()会一直阻塞,知道进程池中的所有工作进程都结束。
有点反常,在使用 map 的情况下是否不再需要 join?
笔者自己试了下,确实不需要在 pool.map 后添加 join。
作者:山花
链接:https://juejin.cn/post/7350181789531815987
评论