【发布时间】:2013-12-31 13:05:37
【问题描述】:
我相信微软声称泛型在处理引用类型时比使用普通多态更快。但是,以下简单测试(64 位 VS2012)将表明并非如此。使用多态性,我通常会加快 10% 的秒表时间。我是否误解了结果?
public interface Base { Int64 Size { get; } }
public class Derived : Base { public Int64 Size { get { return 10; } } }
public class GenericProcessor<TT> where TT : Base
{
private Int64 sum;
public GenericProcessor(){ sum = 0; }
public void process(TT o){ sum += o.Size; }
public Int64 Sum { get { return sum; } }
}
public class PolymorphicProcessor
{
private Int64 sum;
public PolymorphicProcessor(){ sum = 0; }
public void process(Base o){ sum += o.Size; }
public Int64 Sum { get { return sum; } }
}
static void Main(string[] args)
{
var generic_processor = new GenericProcessor<Derived>();
var polymorphic_processor = new PolymorphicProcessor();
Stopwatch sw = new Stopwatch();
int N = 100000000;
var derived = new Derived();
sw.Start();
for (int i = 0; i < N; ++i) generic_processor.process(derived);
sw.Stop();
Console.WriteLine("Sum ="+generic_processor.Sum + " Generic performance = " + sw.ElapsedMilliseconds + " millisec");
sw.Restart();
sw.Start();
for (int i = 0; i < N; ++i) polymorphic_processor.process(derived);
sw.Stop();
Console.WriteLine("Sum ="+polymorphic_processor.Sum+ " Poly performance = " + sw.ElapsedMilliseconds + " millisec");
更令人惊讶(和令人困惑)的是,如果我将类型转换添加到处理器的多态版本,如下所示,它的运行速度始终比泛型版本快约 20%。
public void process(Base trade)
{
sum += ((Derived)trade).Size; // cast not needed - just an experiment
}
这里发生了什么?我知道泛型在处理原始类型时可以帮助避免昂贵的装箱和拆箱,但我在这里严格处理引用类型。
【问题讨论】:
-
你能发布一个关于泛型对于引用类型更快的说法的引用吗?
-
使用
structs 的泛型更快,因为它们允许您避免装箱/拆箱(您必须将参数声明为object以使其与int和@ 一起使用987654326@ 例如)。我对泛型使用引用类型更快一无所知。你能提供任何有关这方面的资料吗? -
对微优化进行基准测试是非常困难的。在尝试对此类操作进行基准测试时,您可能会遇到 很多 的陷阱。通常,除非您对此非常有经验,否则您的结果几乎完全代表您对代码进行基准测试的缺陷的可能性非常高,而不是您正在测量的代码的性能差异。当您正在测量的代码耗时足以显着超过基准测试框架时,此类错误不会使您的结果无效。
-
愚蠢的基准是愚蠢的。
-
我不熟悉这种说法,测试一个您无法清楚识别的说法似乎很奇怪。我的怀疑是,在历史上的某个地方,实际的主张被误记或抄写了。例如,最初的主张可能是,如果您有
struct S<T>{public T item;},那么访问数组S<C>[]的成员比访问C[]的数组(如果C 是未密封的类类型)更快。这是真实的;如果元素类型是结构,抖动可以消除对不安全数组协方差的检查。
标签: c# performance generics