我正在尝试在 Python (Windows Server 2012) 中实现多处理,并且无法达到我期望的性能改进程度。特别是,对于一组几乎完全独立的任务,我希望通过额外的核心实现线性改进。
我知道——尤其是在 Windows 上——打开新进程会产生开销[1],并且底层代码的许多怪癖可能会阻碍一个干净的趋势。但理论上,对于完全并行化的任务[2] ,趋势最终仍应接近线性;或者如果我正在处理部分串行任务[3] ,则可能是逻辑的。
N_cores=36
但是,当我在质数检查测试函数(下面的代码)上运行 multiprocessing.Pool 时,在我进入预期性能之前,我得到了一个几乎完美的平方根关系(我的服务器上的物理内核数)额外的逻辑核心。
这是我的性能测试结果图:(
“标准化性能”是[具有1 个CPU 核心的运行时间]除以[具有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 多线程不兼容。