英文:
Performance difference between generic and non generic method
问题
让我们以示例为例,假设我们想要处理线性代数,使用不同类型的矩阵。并且我们有一个自定义的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)
我是否遗漏了什么?是否有办法通过泛型获得与直接调用相同的性能?
已安装的Framework版本为4.8,目标Framework版本为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;
}
}
}
英文:
Let's say for the sake of the example that we want to work on linear algebra, with different type of matrices. And that we have a custom Matrix class that implements :
interface IMatrix
{
double this[int i, int j] { get; set; }
int Size { get; }
}
I want to implement Matrix multiplication. I was under the impression that both methods :
static void Multiply<TMatrix>(TMatrix a, TMatrix b, TMatrix result) where TMatrix : IMatrix
and
static void Multiply(Matrix a, Matrix b, Matrix result)
(with similar implementation of course) Would internally produce the exact same IL and hence the same performances. It is not the case : the first one is four times slower than the second one. Looking at the IL, it seems the generic one is similar to a call through interface :
static void Multiply(IMatrix a, IMatrix b, IMatrix result)
Am I missing something ? Is there any way to get the same performances with generics than with a direct call ?
Installed Framework 4.8, Target Framework : 4.7.2 (also tested with .Net Core 3)
Method implementation :
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;
}
}
}
答案1
得分: 4
.NET只会为所有引用类型生成一次通用方法的代码。而且该代码必须通过IMatrix
接口调用,因为不同的实现类型可能使用不同的方法实现该接口。所以这只是一个接口调用。
然而,如果你将Matrix定义为struct
而不是class
,JIT编译器将生成通用方法的类型特定实现,在这种情况下,接口调用可以被优化掉。
英文:
.NET will only generate code for a generic method once for all reference types. And that code must call through the IMatrix
interface, as the various implementing types might implement the interface with different methods. So it simply is an interface call.
However if you make Matrix a struct
instead of a class
the JITter will generate a type-specific implementation of the generic methods, and in that the interface call can be optimized away.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论