.NET数组比IronPython中的列表慢?

时间:2011-06-01 10:23:20

标签: .net python ironpython

我在IronPython中根据代码here进行了以下矩阵乘法基准测试:

from System import Random
from System.Diagnostics import Stopwatch

def zero(m,n):
    # Create zero matrix
    new_matrix = [[0 for row in range(n)] for col in range(m)]
    return new_matrix

def rand(m,n):
    # Create random matrix
    rnd = Random(1)
    new_matrix = [[rnd.NextDouble() for row in range(n)] for col in range(m)]
    return new_matrix

def show(matrix):
    # Print out matrix
    for col in matrix:
        print col 

def mult(matrix1,matrix2):
    # Matrix multiplication
    if len(matrix1[0]) != len(matrix2):
        # Check matrix dimensions
        print 'Matrices must be m*n and n*p to multiply!'
    else:
        # Multiply if correct dimensions
        watch = Stopwatch()
        print 'mult1 start....'
        watch.Start()
        new_matrix = zero(len(matrix1),len(matrix2[0]))
        for i in range(len(matrix1)):
            for j in range(len(matrix2[0])):
                for k in range(len(matrix2)):
                    new_matrix[i][j] += matrix1[i][k]*matrix2[k][j]
        watch.Stop()
        print 'mult1 end.'
        print watch.ElapsedMilliseconds
        return new_matrix

from System import Array

def ListToArray(matrix):
    n = len(matrix)
    m = len(matrix[0])
    a = Array.CreateInstance(float, n, m)
    for i in range(n):
        for j in range(m):
            a[i,j] = matrix[i][j]
    return a


def mult2(matrix1, matrix2):

    N = len(matrix1)
    K = len(matrix2)
    M = len(matrix2[0])

    m1 = ListToArray(matrix1)
    m2 = ListToArray(matrix2)
    res = ListToArray(rand(len(matrix1), len(matrix2[0])))

    watch = Stopwatch()
    print 'mult2 start...'
    watch.Start()
    for i in range(N):
        for j in range(M):
            for k in range(K):
                res[i,j] += m1[i,k]*m2[k,j]
    watch.Stop()
    print 'mult2 ends.'
    print watch.ElapsedMilliseconds
    return res


if __name__ == '__main__':
    #a = rand(280,10304)
    #b = rand(10304,280)

    a = rand(280,10)
    b = rand(10,280)

    c = mult2(a, b)
    d = mult(a, b)

我想尝试两个大矩阵(280乘10304和10304乘208),但两个版本都不能在短时间内产生结果。

然后我尝试了一个小得多的(如代码中所示),结果如下:

mult2 : 7902 ms
mult1 : 420 ms

表示在IronPython中使用.NET数组比python List慢得多。

另请注意,C#对两个大矩阵使用约12秒。 IronPython已经在10K倍的小盒子上花了很多钱。我不确定我的计算机中的IronPython设置是否错误,如果没有,IronPython对于数字代码来说真的很慢。

4 个答案:

答案 0 :(得分:2)

对于您的特定问题,我认为问题是boxing - 在IronPython中,列表项(以及所有其他变量)都存储在框中,因此仅对框内值进行操作。但是,CLR数组元素没有装箱,因此IronPython必须在从数组中提取它们时将它们装箱,然后在返回的路上取消装箱.C#可以对未装箱的值进行操作,并进行一系列其他优化使IronPython没有快速制作数组。

如果你想快速数学数学,NumPy for IronPython可能是更好的选择。

答案 1 :(得分:1)

在我们的项目中,我们试图避免使用.Net类,直到这变得非常必要。我想没有任何特别需要使用Array进行矩阵乘法,因为python为您提供了几种处理矩阵,集合或numpy等矩阵的方法。

答案 2 :(得分:0)

使用高级语言处理矩阵时,您可能会以某种方式降低速度。如果你想在.net中这样做,试试http://numerics.mathdotnet.com/ - 他们已经完成了改善矩阵运算的可能性。

这并不能解释为什么你会看到差异,但如果你正在寻找一些快速解决方案,可能会有所帮助。

答案 3 :(得分:0)

我的猜测是,与普通的Python列表相比,杀死性能的是多维数组的使用。我可以很容易地看到这是一条缓慢的路径,如果你自己切换到阵列数组或计算索引,你可以看到一个大的加速。

其他人指出,这不是像Python这样的动态语言的最佳代码。但IronPython的一大好处就是可以轻松无缝地引入C#片段来加速这样的案例。