python多进程和多线程的区别

我有一个朋友在他的电脑上玩一个很棒的游戏时突然遇到一个标志。
他叹了口气,打开任务管理器,发现CPU搜寻进程正忙着设置几乎所有的资源和内存。
他回忆起自己在研究操作系统时,堪称进程和线程大师。
起初他觉得这些概念很复杂,但是当他这次遇到问题的时候,他突然发现这些知识还是很有用的。

“等一下,我还记得老师说过,每个进程都有自己的内存空间,所以如果游戏崩溃了,应该只影响自己的进程,而不会影响其他应用程序。
”他对自己说。

如果用这个例子来解释进程和线程的区别,我的思考会更加直观。
想象一下你正在厨房做饭。
当配偶清洗和切蔬菜时,你则负责炸薯条。
在这个比喻中,厨房就像一个流程,你们两个就像线程,各自承担不同的职责,但都在同一个厨房(流程)中工作。

“那如果做饭的时候需要临时去市场买调料,我现在可以停下来吗?我的爱人可以继续吗?”他问道。

我微笑着回答:“当然,线程可以分开运行,但是你也要注意这一点。
如果你做错了,比如突然停止做饭,没有火,那就很危险了。

我们一边聊天一边解决问题,我朋友的游戏终于可以恢复运行了。
那天晚上我们讨论了很多关于工作系统、进程和线程的问题,感觉受益匪浅。

为什么在Python里推荐使用多进程而不是多线程

说白了,Python多核CPU编程的主要悖论就是GIL——全局解释器锁,它阻止了同一个进程中的多个线程真正的并行。

先来说最重要的一点:GIL本质上是一个“护照”。
在单核CPU下,多线程只是并发,而不是并行,因为只有一个线程可以同时执行带证书的任务(我去年跑高并发爬虫项目时,单核服务器的8 线程CPU利用率一直在1 5 %左右)。
还有一个问题是,对于IO密集型任务,多线程确实可以提高效率(比如处理3 000个请求时,线程A等网络响应,可以使用线程B),但在CPU密集型任务中,重复切换GIL中的线程会降低性能(我们优化了图像处理脚本,发现双核机器上4 个线程相比1 个线程慢了3 0%)。
还有一个重要的细节:多线程在多核机器上问题更大,因为CPU0释放GIL后,其他核心的线程必须赶上。
结果往往一抓到就被CPU0抢走。
这种类型的“线程抖动”会导致 CPU 使用率降至 5 0% 以下。

我最初认为Python 3 中更好的定时器可以完全解决问题,但后来发现我错了——定时器使CPU密集型任务的GIL释放更容易,但并行性瓶颈仍然存在。
等等,还有一件事:单核和多线程切换时,被唤醒的线程总能立即获取GIL,但多核下,其他核心线程必须等待。
这是效率损失的关键。

所以结论很简单:如果你想让多核CPU满负荷运行,就使用多进程即可。
每个进程都有自己独立的GIL,可以进行真正的并行计算(去年我们用multiprocessing重建了数据库同步模块,8 核服务器的速度直接翻倍)。
不过,需要注意的是:多个进程会消耗更多的内存(每个进程都必须重新启动虚拟机),这一点很多人都没有注意到。