改进Python + numpy数组分配/初始化性能

时间:2014-07-03 14:01:45

标签: python c performance numpy

我正在编写一个python程序,使用DLL的一些外部功能。 我的问题是在C代码中传入和传出矩阵(在python中的numpy数组),现在我使用以下代码从DLL接收数据:

peak_count = ct.c_int16()
peak_wl_array = np.zeros(512, dtype=np.double)
peak_pwr_array = np.zeros(512, dtype=np.double)

res = __dll.DLL_Search_Peaks(ctypes.c_int(data.shape[0])
                             ctypes.c_void_p(data_array.ctypes.data),
                             ctypes.c_void_p(peak_wl_array.ctypes.data),
                             ctypes.c_void_p(peak_pwr_array.ctypes.data),
                             ct.byref(peak_count))

它就像一个魅力,但我的问题是numpy分配速度 - 即使没有调用DLL(只是评论)我已经 3.1秒每100次电话

它只是使用np.zeros()分配并使用ctypes.c_void_p(D.ctypes.data)获取可写指针

我需要每秒处理大约20,000个电话,所以几乎所有时间都花在分配内存上。

我想到了cython,但它不会加速numpy数组,所以我没有任何利润。

是否有更快的方式从C编写的DLL接收类似矩阵的数据。

1 个答案:

答案 0 :(得分:2)

内存操作既昂贵又不稳定。

如果您要分配大量数组,那么查看是否可以只进行一次分配是个好主意,并使用视图或子数组只使用数组的一部分:

import numpy as np

niters=10000
asize=512

def forig():
    for i in xrange(niters):
        peak_wl_array = np.empty((asize), dtype=np.double)
        peak_pwr_array = np.empty((asize), dtype=np.double)

    return peak_pwr_array


def fviews():
    peak_wl_arrays  = np.empty((asize*niters), dtype=np.double)
    peak_pwr_arrays = np.empty((asize*niters), dtype=np.double)

    for i in xrange(niters):
        # create views
        peak_wl_array  = peak_wl_arrays[i*asize:(i+1)*asize]
        peak_pwr_array = peak_pwr_arrays[i*asize:(i+1)*asize]
        # then do something

    return peak_pwr_emptys


def fsubemptys():
    peak_wl_arrays  = np.empty((niters,asize), dtype=np.double)
    peak_pwr_arrays = np.empty((niters,asize), dtype=np.double)

    for i in xrange(niters):
        # do something with peak_wl_arrays[i,:]

    return peak_pwr_emptys


import timeit

print timeit.timeit(forig,number=100)
print timeit.timeit(fviews,number=100)
print timeit.timeit(fsubemptys,number=100)

跑步给出

3.41996979713
0.844147920609
0.00169682502747

请注意,如果您正在使用(比如说)np.zeros,那么您将花费大部分时间来初始化内存,而不是分配内存,这总是会花费更长的时间,消除这些方法之间的大部分差异:

4.20200014114
5.43090081215
4.58127593994

新系统上主内存的良好单线程带宽将达到~10GB / s(10亿双/秒),因此它总会占用

  

1024双打/通话/(10亿双打/秒)~1微秒/通话

将内存归零,这已经是你所看到的重要时间。但是,如果在进行调用之前初始化单个大型数组,则执行的总时间将相同,但每次调用的延迟时间会更短。