为了举例说明,我们要处理具有不同类型矩阵的线性代数。并且我们有一个自定义的Matrix类,该类实现:
interface IMatrix
{
double this[int i, int j] { get; set; }
int Size { get; }
}
我想实现矩阵乘法。我对这两种方法都印象深刻:
static void Multiply<TMatrix>(TMatrix a, TMatrix b, TMatrix result) where TMatrix : IMatrix
和
static void Multiply(Matrix a, Matrix b, Matrix result)
((当然具有类似的实现方式)将在内部产生完全相同的IL,因此具有相同的性能。事实并非如此:第一个比第二个慢四倍。从IL来看,通用类类似于通过接口进行的调用:
static void Multiply(IMatrix a, IMatrix b, IMatrix result)
我想念什么吗?与直接调用相比,有什么方法可以使泛型获得相同的性能吗?
已安装框架4.8,目标框架:4.7.2(也已通过.Net Core 3测试)
方法实现:
static void Multiply(Matrix a, Matrix b, Matrix result)
{
for (int i = 0; i < a.Size; i++)
{
for (int j = 0; j < a.Size; j++)
{
double temp = 0;
for (int k = 0; k < a.Size; k++)
{
temp += a[i, k] * b[k, j];
}
result[i, j] = temp;
}
}
}
。NET将为所有引用类型仅一次为通用方法生成代码。该代码必须通过IMatrix
接口调用,因为各种实现类型可能会使用不同的方法来实现该接口。因此,它只是一个接口调用。
但是,如果将Matrix设为struct
而不是class
,则JITter将生成通用方法的特定于类型的实现,并且可以优化接口调用。