我正尝试在 Python (Windows Server 2012) 中实现多处理,但无法达到我期望的性能改进程度。特别是,对于一组几乎完全独立的任务,我希望通过额外的核心实现线性改进。
我明白——尤其是在 Windows 上——打开新进程会产生开销 [1] ,并且底层代码的许多怪癖可能会阻碍干净的趋势。但理论上,对于完全并行化的任务,趋势最终仍应接近线性 [2] ;或者如果我正在处理部分串行任务,则可能是逻辑的 [3] .
但是,当我在质数检查测试函数(下面的代码)上运行 multiprocessing.Pool 时,我得到了接近完美的平方根关系,直到 N_cores=36
(我的服务器上的物理内核数量)在我进入额外的逻辑内核时达到预期性能之前。
Here是我的性能测试结果图:
(“标准化性能”是[具有1 CPU 核心]的运行时间除以< strong>[ 具有 N 个 CPU 内核的运行时])。
多处理的返回率急剧下降是否正常?还是我的实现遗漏了什么?
import numpy as np
from multiprocessing import Pool, cpu_count, Manager
import math as m
from functools import partial
from time import time
def check_prime(num):
#Assert positive integer value
if num!=m.floor(num) or num<1:
print("Input must be a positive integer")
return None
#Check divisibility for all possible factors
prime = True
for i in range(2,num):
if num%i==0: prime=False
return prime
def cp_worker(num, L):
prime = check_prime(num)
L.append((num, prime))
def mp_primes(omag, mp=cpu_count()):
with Manager() as manager:
np.random.seed(0)
numlist = np.random.randint(10**omag, 10**(omag+1), 100)
L = manager.list()
cp_worker_ptl = partial(cp_worker, L=L)
try:
pool = Pool(processes=mp)
list(pool.imap(cp_worker_ptl, numlist))
except Exception as e:
print(e)
finally:
pool.close() # no more tasks
pool.join()
return L
if __name__ == '__main__':
rt = []
for i in range(cpu_count()):
t0 = time()
mp_result = mp_primes(6, mp=i+1)
t1 = time()
rt.append(t1-t0)
print("Using %i core(s), run time is %.2fs" % (i+1, rt[-1]))
注意:我知道对于这个任务,实现多线程可能会更有效,但是这个脚本是一个简化模拟的实际脚本是由于 GIL,与 Python 多线程不兼容。
最佳答案
<子> @KellanM值得[+1]进行定量性能监控
am I missing something with my implementation?
是的,你从所有add-on costs中抽象出来流程管理。
虽然您表达了对“具有额外核心的线性改进。”的期望,但由于多种原因,这在实践中几乎不会出现(甚至共产主义的炒作也失败了免费提供任何东西)。
Gene AMDAHL 制定了 yield 递减初始法则。
最近,re-formulated version , 还考虑了流程管理{setup|terminate}-附加开销成本的影响,并试图应对原子性处理(给定大型工作包在大多数常见的编程系统中,有效负载不能轻易地重新定位/重新分配到可用的空闲 CPU 内核池(除了一些确实特定的微调度艺术,例如在 Semantic Design 的 PARLANSE 或 LLNL 的 SISAL 中展示的那些在过去)。
最好的下一步是什么?
如果确实对这个领域感兴趣,人们可能总是通过实验测量和比较流程管理的实际成本(加上数据流成本,加上内存分配成本,......直到流程终止和结果重新组装在主进程中)以便定量地公平记录和评估使用更多 CPU 内核的附加成本/ yield 比(这将在 python
中重新设置整个 python 解释器在第一个有用的操作将在第一个生成和设置过程中执行之前的状态,包括它的所有内存状态。
表现不佳(对于下面的前一种情况)
如果不是灾难性的影响(对于下面的第二种情况),
要么是设计不当的资源映射策略,要么是
“预订不足”-来自CPU-核心池的资源
或
“超额预订”-来自RAM-space
池的资源是discussed also here
上面重新制定的阿姆达尔定律的链接将帮助您评估 yield 递减点,即付出的比以往任何时候都多。
Hoefinger et Haunschmid 实验可以作为一个很好的实践证据,越来越多的处理节点(无论是本地 O/S 管理的 CPU 核心,还是 NUMA 分布式架构节点)如何将开始降低由此产生的性能,
其中 yield 递减点(在与开销不可知的阿姆达尔定律中得到证明)
实际上将开始成为一个点,之后您付出的比得到的多。:
最后但同样重要的是,
NUMA/非局部性问题引起了人们的关注,讨论了针对 HPC 级调整(缓存中/RAM 中计算策略)的缩放,并且可能 - 作为副作用 - 有助于检测缺陷(如由上面的 @eryksun 报告)。人们可以通过使用 lstopo
工具随意查看自己的平台实际 NUMA 拓扑,以查看抽象,操作系统正在尝试使用,一旦安排了“just"-[CONCURRENT]
task execution on such a NUMA-resources-topology:
关于Python 多处理性能仅随所用内核数的平方根提高,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50221512/