我在Macbook Pro上运行了以下示例代码,使用的是Python 3.4.2版本,numpy版本为1.9.1,matplotlib版本为1.4.2。该电脑有4个物理CPU(与Mac硬件架构提供的一些用例中的“虚拟”CPU不同):
import numpy as np
import matplotlib.mlab as mlab
import time
import multiprocessing
size = 500
Y = np.arange(size)
X = np.arange(size)
x, y = np.meshgrid(X, Y)
u = x * np.sin(5) + y * np.cos(5)
v = x * np.cos(5) + y * np.sin(5)
test = x + y
tic = time.clock()
test_d = mlab.griddata(
x.flatten(), y.flatten(), test.flatten(), x+u, y+v, interp='linear')
toc = time.clock()
print('Single Processor Time={0}'.format(toc-tic))
xi = x + u
yi = y + v
nprocs = 4
jump = int(size/nprocs)
def wrapper(x, y, z, xi, yi, q):
test_w = mlab.griddata(x, y, z, xi, yi, interp='linear')
q.put(test_w)
ticm = time.clock()
queue, process = [], []
for n in range(nprocs):
queue.append(multiprocessing.Queue())
if n == (nprocs-1):
finalidx = size
else:
finalidx = (n + 1) * jump
argtuple = (x.flatten(), y.flatten(), test.flatten(),
xi[:,(n*jump):finalidx], yi[:,(n*jump):finalidx], queue[-1])
process.append(multiprocessing.Process(target=wrapper, args=argtuple))
process[-1].start()
test_m = np.asarray([[] for s in range(size)])
for q, p in zip(queue, process):
test_m = np.concatenate((test_m, q.get()), axis=1)
p.join()
tocm = time.clock()
print('Multiprocessing Time={0}'.format(tocm-ticm))
assert np.all(test_d == test_m)
我得到了以下结果:
/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/matplotlib/tri/triangulation.py:110: FutureWarning: comparison to `None` will result in an elementwise object comparison in the future.self._neighbors)
Single Processor Time=8.495998
Multiprocessing Time=2.249938
我不太确定是什么原因导致了triangulation.py的“未来警告”(显然,我的matplotlib版本不喜欢最初提供的问题输入值的某些内容),但无论如何,多进程似乎确实实现了期望的加速比8.50 / 2.25 = 3.8,(编辑:见评论),大约是我们预计4个CPU的机器可以达到的4倍左右。并且最后的断言语句也成功执行,证明两种方法得到相同的答案,因此尽管有稍微奇怪的警告信息,我认为上面的代码是一个有效的解决方案。
EDIT:一位评论者指出,我的解决方案以及原作者发布的代码片段都可能使用了错误的方法
time.clock()
来测量执行时间;他建议使用
time.time()
。我也开始认同他的观点。(深入研究Python文档后,我仍然不确定这个解决方案是否100%正确,因为新版本的Python似乎已经弃用了
time.clock()
,转而使用
time.perf_counter()
和
time.process_time()
。但无论如何,我同意无论
time.time()
是否绝对正确地进行了这个测量,它仍然比我之前使用的
time.clock()
更正确。)
假设评论者的观点是正确的,则意味着我认为我所测量到的大约4倍加速是错误的。
然而,这并不意味着底层代码本身没有正确地并行化;相反,它只是意味着在这种情况下,并行化实际上并没有帮助;将数据分割并在多个处理器上运行并没有改进任何东西。为什么会这样?其他用户已经指出,至少在numpy/scipy中,一些函数可以在多个核心上运行,而另一些则不行,对于最终用户来说,试图弄清哪些函数是哪些函数是一个非常具有挑战性的研究项目。根据这个实验的结果,如果我的解决方案在Python中正确实现了并行化,但没有进一步的加速,那么我认为最简单的可能解释是matplotlib可能也在"幕后"以编译的C++库的形式并行化了一些其功能,就像numpy/scipy已经做的那样。假设是这样的话,那么这个问题的正确答案就是:如果底层的C++库已经悄悄地在多个内核上运行,那么在Python中进一步并行化也无济于事。
test= xx+yy
- OYRM