提问人:Mi-Shell 提问时间:11/10/2023 最后编辑:Mi-Shell 更新时间:11/10/2023 访问量:80
Python 多处理正在降低性能
Python multiprocessing is deacreasing performance
问:
为了理解并行化,我在模块多处理上编写了一个玩具脚本。我绘制了下图,结论是我的实现通过添加多个进程使性能变差。 例如,我的代码创建了一个包含 10 000 个元素的列表,然后并行计算其元素的总和。每个进程都必须在其自己的子列表中执行元素的总和。
使用 1 个进程,需要 0.78 秒来计算总和。2 个进程,1,29 秒,3 个进程,1,93 秒。看我的图表:
法典:
import multiprocessing
import time
import math
import numpy as np
def sum_list(mylist,result,index_min,index_max):
for i in range(index_min,index_max):
result.value += mylist[i]
if __name__ == "__main__":
f = lambda x: np.sin(x)*np.cos(x)
X = np.linspace(0,1,10000)
mylist=f(X) #creating the list to sum
size = len(mylist)
result = multiprocessing.Value('d')
result.value = 0
processes = []
n = 10
#creating processes
start = time.perf_counter()
for p in range(n):
index_min = int(p*size/n)
index_max = int((p+1)*size/n)
print(index_min,index_max)
processes.append( multiprocessing.Process(target = sum_list,args = (mylist,result,index_min,index_max)) )
#starting processes
for process in processes:
process.start()
#end processes
for process in processes:
process.join()
end = time.perf_counter()
print('time ellapsed :', end-start, 'seconds. ')
显然,由于列表的大小是固定的,我希望进程只有一个小的子列表要求和,并且由于它们同时执行,因此总计算时间应该会减少。
我尝试了很多不同数量的进程和两种不同的硬件架构,但问题就在那里。我错过了什么吗?是因为每次一个进程必须写入结果时,它都必须与其他进程通信,从而降低性能吗?
谢谢你的回答。
答:
“Python 多处理正在降低性能”
是的。
还有其他问题吗?
(对不起,开玩笑)
与多线程或线程内并发相比,启动多进程本身在系统资源方面成本很高。然后,从外部进程传输的所有数据,即使返回值由实例封装,也涉及一些其他资源。(通常序列化和反序列化传递的每个数据项 + 同步代码)。multiprocessing.Value()
因此,值得使用“实际工作负载”,或者设计良好的演示工作负载,这些工作负载实际上将利用系统资源。
更具体地说,你的“工作负载”实际上是在后台这样做的:向管理器进程发送信号 多处理生成以协调共享-多处理数据,请求其当前 ,并且 sum 操作本身实际上是在这个管理器进程中执行的(无论你做了多少个工作进程: 为了保证算子的原子性质,总和是在单个进程中执行的, 并在锁下阻止其他进程实际并行运行。你这样做是为了你所有的价值观。result.value += mylist[i]
result.value
+=
更改您的工作代码以一次将其所有份额相加,并在每个进程中增加一次值,您应该会得到很大的改进。不过,操作仍然足够简单,多处理开销可能仍大于您的收益。result.value
sum
不过,值得一提的是:显而易见的收获是,多进程能够以一种直接的方式同时在多个 CPU 内核中运行 Python 代码 - 使用 GIL(全局解释器锁),这在 Python 3.12 之前的版本中是不可能的(并且在 Python 3.12 中使用 Python 解释器实例很难实现)。
我的建议是,既然你正在玩这个,那就继续玩,直到你对使用线程、多进程和生成其中的 2 或 3 个线程(或 20-30 个)以及具有数百万个项目的工作负载之间的区别有深刻的了解。
另一个需要调整和调整的参数是将多处理启动方法更改为 - https://docs.python.org/3/library/multiprocessing.html#multiprocessing.set_start_method - Mac OS 和 Windows 的默认值是“Spawn” - 您应该通过使用“fork”(在 Windows 上不可用)来获得更好的性能multiprocessing.set_start_method
此外,在 Python 3.12 中,您可以尝试使用子解释器 - 在 Mac 或 Linux 中,您可以安装“额外解释器”包(警告:此阶段的 alpha 软件),或使用(在任何操作系统上)并按照 https://peps.python.org/pep-0554/ 上的文档进行操作import _xxsubinterpreters as interpreters
(免责声明:我是包的作者)extrainterpreters
评论
multiprocessing.Value
Process Pool
the time to start N python interpreters
Process Pool
sum
sum