为何Python中继承Process类的多进程运行速度慢于其他方式?
为什么继承Process类实现的进程比target方式运行慢?
我在学习多线程与多进程技术时做了个实验,发现继承Process类实现的进程运行速度远慢于直接用target参数创建进程的方式,实验代码和结果如下:
from time import time from multiprocessing import Process def count(n): while n > 0: n -= 1 t0 = time() count(100_000_000) count(100_000_000) print(time() - t0) pr1 = Process(target=count, args=(100_000_000,)) pr2 = Process(target=count, args=(100_000_000,)) t0 = time() pr1.start(); pr2.start() pr1.join(); pr2.join() print(time() - t0) class Proc(Process): def __init__(self, num): super().__init__() self.num = num def run(self): while self.num > 0: self.num -= 1 pro1 = Proc(100_000_000) pro2 = Proc(100_000_000) t0 = time() pro1.start(); pro2.start() pro1.join(); pro2.join() print(time() - t0) # 运行结果: # casual time : 7.1526172161102295 # two processes time : 3.7792704105377197 # two extended processes time : 9.833416223526001
核心原因:实例属性 vs 局部变量的访问效率差异
问题出在循环内部的变量访问方式:
- 在
count函数中,n是局部变量,Python对局部变量的访问是直接通过栈帧索引获取,速度极快。 - 而在继承Process的
Proc.run方法中,每次循环都要访问self.num——这是实例属性,每次访问都需要经过Python的属性查找机制(调用__getattribute__),还要处理可能的属性拦截、继承链查找等逻辑,单次访问的开销虽然小,但在1亿次循环的放大下,整体耗时就会显著增加。
验证与修复
如果把run方法修改为先将实例属性赋值给局部变量,再进行循环,就能消除这个差异:
class Proc(Process): def __init__(self, num): super().__init__() self.num = num def run(self): # 将实例属性转为局部变量 n = self.num while n > 0: n -= 1
修改后运行,耗时会和target方式的进程基本一致,因为此时循环中访问的是局部变量,效率和count函数完全相同。
补充说明
两种进程创建方式的启动开销差异极小,不会导致这么大的时间差。真正的元凶是循环内部的变量访问效率被循环次数放大了——1亿次的微小开销累加,最终形成了数秒的差距。
内容的提问来源于stack exchange,提问作者Taras Lavriv
相关产品推荐
相关产品推荐

