python - python的快速二维 float 组(访问/写入)

标签 python arrays optimization cython

对于我的项目使用,我需要在二维数组中存储一定数量(~100x100)的 float 。在函数计算期间,我需要读取和写入数组,并且由于该函数确实是瓶颈(消耗 98% 的时间),所以我确实需要它很快。

我用 numpy 和 cython 做了一些实验:

import numpy
import time
cimport numpy
cimport cython

cdef int col, row

DTYPE = numpy.int
ctypedef numpy.int_t DTYPE_t
cdef numpy.ndarray[DTYPE_t, ndim=2] matrix_c = numpy.zeros([100 + 1, 100 + 1], dtype=DTYPE)

time_ = time.time()
for l in xrange(5000):
    for col in xrange(100):
        for row in xrange(100):
            matrix_c[<unsigned int>row + 1][<unsigned int>col + 1] = matrix_c[<unsigned int>row][<unsigned int>col]
print "Numpy + cython time: {0}".format(time.time() - time_)

但我发现,尽管我进行了所有尝试,使用 python 列表的版本仍然明显更快。

使用列表的代码:

matrix = []
for i in xrange(100 + 1):
    matrix.append([])
    for j in xrange(100 + 1):
        matrix[i].append(0)

time_ = time.time()
for l in xrange(5000):
    for col in xrange(100):
        for row in xrange(100):
            matrix[row + 1][col + 1] = matrix[row][col]
print "list time: {0}".format(time.time() - time_)

结果:

list time: 0.0141758918762
Numpy + cython time: 0.484772920609

我是不是做错了什么?如果没有,有什么可以帮助我改善结果吗?

最佳答案

这是我的代码版本。 共有三个函数,分别处理整数数组、32位 float 组和 double float 组。

from numpy cimport ndarray as ar
cimport numpy as np
import numpy as np
cimport cython
import time

@cython.boundscheck(False)
@cython.wraparound(False)
def access_write_int(ar[int,ndim=2] c, int n):
    cdef int l, col, row, h=c.shape[0], w=c.shape[1]
    time_ = time.time()
    for l in range(n):
        for row in range(h-1):
            for col in range(w-1):
                c[row+1,col+1] = c[row,col]
    print "Numpy + cython time: {0}".format(time.time() - time_)

@cython.boundscheck(False)
@cython.wraparound(False)
def access_write_float(ar[np.float32_t,ndim=2] c, int n):
    cdef int l, col, row, h=c.shape[0], w=c.shape[1]
    time_ = time.time()
    for l in range(n):
        for row in range(h-1):
            for col in range(w-1):
                c[row+1,col+1] = c[row,col]
    print "Numpy + cython time: {0}".format(time.time() - time_)

@cython.boundscheck(False)
@cython.wraparound(False)
def access_write_double(ar[double,ndim=2] c, int n):
    cdef int l, col, row, h=c.shape[0], w=c.shape[1]
    time_ = time.time()
    for l in range(n):
        for row in range(h-1):
            for col in range(w-1):
                c[row+1,col+1] = c[row,col]
    print "Numpy + cython time: {0}".format(time.time() - time_)

为了从 Python 调用这些函数,我运行这个

import numpy as np
from numpy.random import rand, randint

print "integers"
c = randint(0, high=20, size=(101,101))
access_write_int(c, 5000)
print "32 bit float"
c = rand(101, 101).astype(np.float32)
access_write_float(c, 5000)
print "double precision"
c = rand(101, 101)
access_write_double(c, 5000)

以下更改很重要:

  1. 通过使用 [i,j] 形式的索引访问数组来避免对数组进行切片。而不是[i][j]

  2. 定义变量 l , col ,和row ,作为整数,以便 for 循环在 C 中运行。

  3. 使用函数装饰器 @cython.boundscheck(False)和 '@cython.wraparound(False)` 关闭程序关键部分的边界检查和环绕索引。这允许越界内存访问,因此您应该当您确定索引正确时才执行此操作。

  4. 交换最里面的两个for循环,以便您根据数组在内存中的排列方式访问数组。对于较大的阵列来说,这会产生更大的差异。 np.zeros 给出的数组np.random.rand等通常是 C 连续的,因此行存储在连续的 block 中,并且沿着外部 for 中的行改变索引会更快。循环而不是内部循环。如果您想保持 for 循环不变,请考虑在对其运行函数之前对数组进行转置,以便各列位于连续的 block 中。

关于python - python的快速二维 float 组(访问/写入),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17515630/

相关文章:

arrays - 如何用函数递归地填充数组?

java - 为什么我的 for 循环在 Android studio 中给出与 eclipse (java) 相反的不同结果

c++ - 从文件中读取大量数据并以有效的方式解析日期。如何提高海量数据的性能?

java - 替代计划的任务,将来可能会取消

C++20 constexpr std::copy 运行时优化

python - 如何在 python 中获得按创建日期排序的目录列表?

python 3.5 matplotlib 等高线图图例

python - 如何从特定于供应商的数据类型中查找 SQLAlchemy 通用数据类型

python - 写入 Python subprocess.Popen 对象的文件描述符 3

arrays - 为数组中的每个元素找到最后一个较小或相等的数字?