【问题标题】:Python - multiprocessing for matplotlib griddataPython - matplotlib 网格数据的多处理
【发布时间】:2015-07-04 01:46:54
【问题描述】:

在我之前的问题[1] 之后,我想将多处理应用于matplotlib 的griddata 函数。是否可以将网格数据分成 4 个部分,每个部分用于我的 4 个核心?我需要这个来提高性能。

例如,尝试下面的代码,尝试使用不同的 size 值:

import numpy as np
import matplotlib.mlab as mlab
import time

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 'Time=', toc-tic

【问题讨论】:

  • 我不认为你可以应用多处理。也许,这个问题stackoverflow.com/q/7424777/566035 有帮助吗?
  • 示例代码在语法上不正确。您打算如何处理以下行:test= xx+yy
  • 我修复了代码,现在应该可以运行了。
  • 感谢您的贡献:)

标签: python multithreading matplotlib datagrid multiprocessing


【解决方案1】:

我在具有 4 个物理 CPU 的 Macbook Pro(即,与 Mac硬件架构也可用于某些用例):

import numpy as np
import matplotlib.mlab as mlab
import time
import multiprocessing

# This value should be set much larger than nprocs, defined later below
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))

# Put interpolation points into a single array so that we can slice it easily
xi = x + u
yi = y + v
# My example test machine has 4 physical CPUs
nprocs = 4
jump = int(size/nprocs)

# Enclose the griddata function in a wrapper which will communicate its
# output result back to the calling process via a Queue
def wrapper(x, y, z, xi, yi, q):
    test_w = mlab.griddata(x, y, z, xi, yi, interp='linear')
    q.put(test_w)

# Measure the elapsed time for multiprocessing separately
ticm = time.clock()

queue, process = [], []
for n in range(nprocs):
    queue.append(multiprocessing.Queue())
    # Handle the possibility that size is not evenly divisible by nprocs
    if n == (nprocs-1):
        finalidx = size
    else:
        finalidx = (n + 1) * jump
    # Define the arguments, dividing the interpolation variables into
    # nprocs roughly evenly sized slices
    argtuple = (x.flatten(), y.flatten(), test.flatten(),
                xi[:,(n*jump):finalidx], yi[:,(n*jump):finalidx], queue[-1])
    # Create the processes, and launch them
    process.append(multiprocessing.Process(target=wrapper, args=argtuple))
    process[-1].start()

# Initialize an array to hold the return value, and make sure that it is
# null-valued but of the appropriate size
test_m = np.asarray([[] for s in range(size)])
# Read the individual results back from the queues and concatenate them
# into the return array
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))

# Check that the result of both methods is actually the same; should raise
# an AssertionError exception if assertion is not True
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 的预期加速(edit: see cmets),这大约是我们期望的机器的 4 倍左右4 个 CPU。并且最后的断言语句也执行成功了,证明这两种方法得到了相同的答案,所以尽管警告信息有些奇怪,但我相信上面的代码是一个有效的解决方案。


编辑:一位评论者指出,我的解决方案以及原作者发布的代码 sn-p 都可能使用了错误的方法 time.clock() 来测量执行时间;他建议改用time.time()。我想我也正在接受他的观点。 (进一步深入研究 Python 文档,我仍然不相信即使这个解决方案是 100% 正确的,因为较新版本的 Python 似乎已经弃用 time.clock() 以支持 time.perf_counter()time.process_time()。但不管,我确实同意time.time() 是否绝对是进行此测量的最正确方法,它可能仍然比我以前使用的方法更正确,time.clock()。)

假设评论者的观点是正确的,那么这意味着我认为我测量的大约 4 倍的加速实际上是错误的。

但是,这并不意味着底层代码本身没有正确并行化;相反,这只是意味着在这种情况下并行化实际上并没有帮助;拆分数据并在多个处理器上运行并没有改善任何东西。为什么会这样?其他用户有pointed out,至少在 numpy/scipy 中,一些函数在多个内核上运行,而有些则没有,对于最终用户来说,试图找出哪些是哪些是一个非常具有挑战性的研究项目.

根据这个实验的结果,如果我的解决方案在 Python 中正确实现了并行化,但没有观察到进一步的加速,那么我建议最简单的可能解释是 matplotlib 可能也在“在后台并行化它的一些函数” ",可以这么说,在编译的 C++ 库中,就像 numpy/scipy 已经做的那样。假设是这种情况,那么这个问题的正确答案将是无法再做进一步的事情:如果底层 C++ 库一开始就已经在多个内核上静默运行,那么在 Python 中进一步并行化将没有任何好处。

【讨论】:

  • 很遗憾,您没有使用time.clock() 计算挂钟时间(请参阅stackoverflow.com/a/23325328/1510289)。相反,使用time.time() 并注意多处理场景实际上需要更长的时间。不过,这是一个不错的尝试!我也尝试过自己拆分输入值,但没有发现任何加速到griddata()。 :(
  • 抱歉,@stachyra 的回答不正确。用time.time() 替换time.clock(),真正的挂钟性能更差。我的 8-CPU 机器给出:Single Processor Time=8.833 Multiprocessing Time=11.677
  • 我无法启动它...我收到一个错误:“Traceback(最近一次调用最后一次):文件“/usr/lib/python2.7/multiprocessing/process.py”,第 258 行,在 _bootstrap self._target(*self._args, **self._kwargs) 文件“”中,第 11 行,在包装器中 test_w = mlab.griddata(x, y, z, xi, yi , interp='linear') File "/usr/lib/pymodules/python2.7/matplotlib/mlab.py", line 2619, in griddata raise ValueError("output grid must have constant spacing" ValueError: output grid must have constant使用 interp='linear' 时的间距..."
  • @user3601754:您的 matplotlib 版本可能已过时。正如我在回答开头所说的那样,我在 Python 3.4.2 版和 matplotlib 1.4.2 版下运行了上面的代码。我也碰巧在同一台测试机器上安装了较旧的 Python 2.7.5,它使用 matplotlib 版本 1.1.1。当我尝试使用那些旧版本号运行我的解决方案代码时,我得到的错误与你所做的完全相同。尝试将 matplotlib 升级到最新版本,这几乎肯定会解决问题。
猜你喜欢
  • 1970-01-01
  • 2013-01-23
  • 1970-01-01
  • 2015-08-08
  • 2012-05-12
  • 2010-12-16
  • 2011-05-31
  • 1970-01-01
  • 2015-08-05
相关资源
最近更新 更多