.NET数组在IronPython中比列表慢吗?

3 投票
4 回答
923 浏览
提问于 2025-04-16 18:45

我在IronPython中做了一个矩阵乘法的性能测试,参考了这个链接的代码:

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的列表要慢很多。

还注意到C#处理这两个大矩阵大约花了12秒。而IronPython在处理一个小10K倍的案例时已经花了很多时间。我不确定我电脑上的IronPython设置是否有问题,如果没有的话,IronPython在处理数值计算时确实很慢。

4 个回答

0

当你使用高级编程语言来处理矩阵时,速度可能会慢得让你不满意。 如果你想在 .net 环境下进行矩阵运算,可以试试这个网站 http://numerics.mathdotnet.com/ - 他们已经尽力优化了矩阵操作。

这并不是解释你为什么会看到速度差异的答案,但如果你在寻找快速解决方案,这可能会对你有帮助。

1

在我们的项目中,我们尽量不使用 .Net 类,直到真的需要的时候才用。我觉得其实没有必要用数组来做矩阵乘法,因为 Python 提供了很多处理矩阵的方法,比如用列表、集合或者 numpy 库。

2

针对你提到的问题,我觉得主要是因为装箱的原因。在IronPython中,列表里的每个元素(还有其他变量)都是以“装箱”的方式存储的,也就是说,只有经过装箱的值才能被操作。而CLR数组里的元素并不是装箱的,所以当从数组中提取元素时,IronPython需要先把它们装箱,然后在放回去的时候再拆箱。C#可以直接操作那些没有装箱的值,并且有很多其他的优化手段来让数组的操作更快,而这些在IronPython中是没有的。

如果你想进行快速的数值计算,可能NumPy for IronPython会是一个更好的选择。

撰写回答