携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情
1.实现多进程
Process类用来描述一个进程对象。创建子进程的时候,只需要传入一个执行函数和函数的参数,即可完成Process示例的创建。
•start()方法启动进程;
•join()方法实现进程间的同步,等待所有进程退出;
•close()用来阻止多余的进程涌入进程池 Pool造成进程阻塞;
•target是函数名字,需要调用的函数;
•args函数需要的参数,以tuple的形式传入。
2.Pool 类
Pool可以提供指定数量的进程供用户使用,默认是 CPU 核数。当有新的请求提交到Pool的时候,如果池子没有满,会创建一个进程来执行,否则就会让该请求等待;
Pool对象调用join方法,会等待所有的子进程执行完毕;- 调用
join方法之前,必须调用close; - 调用
close之后,就不能继续添加新的Process了。
3.pool.apply_async
apply_async方法用来同步执行进程,允许多个进程同时进入池子。
apply_async是异步非阻塞的。
4.pool.apply
apply(func[, args[, kwds]])
该方法只能允许一个进程进入池子,在一个进程结束之后,另外一个进程才可以进入池子。
apply方法是阻塞的。
意思就是等待当前子进程执行完毕后,再执行下一个进程。
因为apply是阻塞的,所以进入子进程执行后,等待当前子进程执行完毕,再继续执行下一个进程。
5.apply 和 apply_async 的区别
apply是阻塞式的。
首先主进程开始运行,碰到子进程,操作系统切换到子进程,等待子进程运行结束后,再切换到另外一个子进程,直到所有子进程运行完毕。然后,再切换到主进程,运行剩余的部分。
apply_async是异步非阻塞式的。
首先主进程开始运行,碰到子进程后,主进程说:让我先运行个够,等到操作系统进行进程切换的时候,再交给子进程运行。因为我们的程序太短,然而还没等到操作系统进行进程切换,主进程就运行完毕了。想要子进程执行,就告诉主进程:你等着所有子进程执行完毕后,再运行剩余部分。
6.线程:
简单来说,一个进程中包含多个线程,比如打开一个 QQ(进程),然后你一边聊 QQ(一个线程),一边用 QQ 传送文件(一个线程),等等。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程( Thread )。
7.多线程的优点
-
使用线程可以把占据长时间的程序任务放到后台去处理;
-
用户界面可以更加吸引人,比如用户点击了一个按钮,去触发某些事件的处理,可以弹出一个进度条,来显示处理的进度;
-
程序的运行速度可能加快;
-
在一些等待的任务实现上,如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下,我们可以释放一些珍贵的资源,如内存占用等等。
-
每个进程互相独立,不影响主程序的稳定性,子进程崩溃没关系;
-
通过增加 CPU,就很容易扩充性能;
-
可以尽量减少线程加锁/解锁的影响,极大提高性能,就算是线程运行的模块算法效率低也没关系;
-
每个子进程都有 2GB 地址空间和相关资源,总体能够达到的性能上限非常大。
多进程缺点:
- 逻辑控制复杂,需要和主程序交互;
- 需要跨进程边界,如果有大量数据需要传送,就不太好,适合少量数据传送、密集运算,多进程调度开销比较大;
- 最好是多进程和多线程结合,即根据实际的需要,每个 CPU 开启一个子进程,这个子进程开启多线程,可以为若干同类型的数据进行处理。当然你也可以利用多线程 + 多 CPU + 轮询方式来解决问题……;
- 方法和手段是多样的,关键是自己看起来,实现方便又能够满足要求,代价也合适。