如何使用 Parallel.ForEach 将 2 个矩阵相乘?

How to multiply 2 matrices using Parallel.ForEach?

有一个函数可以像往常一样将两个矩阵相乘

public IMatrix Multiply(IMatrix m1, IMatrix m2)
        {
            var resultMatrix = new Matrix(m1.RowCount, m2.ColCount);
            for (long i = 0; i < m1.RowCount; i++)
            {
                for (byte j = 0; j < m2.ColCount; j++)
                {
                    long sum = 0;
                    for (byte k = 0; k < m1.ColCount; k++)
                    {
                        sum += m1.GetElement(i, k) * m2.GetElement(k, j);
                    }

                    resultMatrix.SetElement(i, j, sum);
                }
            }

            return resultMatrix;
        }

这个函数应该用Parallel.ForEach线程重写,我试过这样

public IMatrix Multiply(IMatrix m1, IMatrix m2)
        {
            // todo: feel free to add your code here

            var resultMatrix = new Matrix(m1.RowCount, m2.ColCount);
            
            Parallel.ForEach(m1.RowCount, row =>
            {
                for (byte j = 0; j < m2.ColCount; j++)
                {
                    long sum = 0;
                    for (byte k = 0; k < m1.ColCount; k++)
                    {
                        sum += m1.GetElement(row, k) * m2.GetElement(k, j);
                    }

                    resultMatrix.SetElement(row, j, sum);
                }
            });

            return resultMatrix;
        }

但是循环中的类型参数有错误。我该如何解决?

只需使用 Parallel.For 而不是 Parallel.Foreach,这应该让你保持与 non-parallel 版本完全相同的主体:

Parallel.For(0, m1.RowCount, i =>{
   ...
}

请注意,只有相当大的矩阵才能从并行化中获益,因此如果您正在为图形处理 4x4 矩阵,则不宜采用这种方法。

矩阵相乘的一个问题是您需要为最内层循环中的一个矩阵的每一行访问一个值。您的处理器可能难以缓存此访问模式,从而导致大量缓存未命中。因此,一个相当简单的优化是将整个列复制到一个临时数组,并在读取下一列之前执行所有需要该列的计算。这让所有内存访问都很好、线性且易于缓存。这总体上会做更多的工作,但更好的缓存利用率很容易使它获胜。还有更多缓存高效的方法,但复杂度也有增加的趋势。

另一个优化是使用 SIMD,但这可能需要特定于平台的代码以获得最佳性能,并且可能需要更多的工作。但是您也许能够找到已经优化过的库。

但也许最重要的是,剖析您的代码。简单的事情很容易耗费大量时间。例如,您正在使用一个接口,因此如果您可能对每个无法内联的内存访问调用一个虚拟方法,与直接数组访问相比,可能会导致严重的性能损失。

ForEach 接收一个集合,IEnumerable 作为第一个参数,m1.RowCount 是一个数字。 可能 Parallel.For() 就是你想要的。