我在执行各种常见操作(如装箱,投射,对象分配等)的微观基准测试时偶然发现了这种非常奇怪的行为,以便更好地学习如何实现我一直在努力的数据结构库。
基本上,在泛型类中使用静态构造函数(即使它是空的)会导致任何方法调用都非常慢,但前提是类型参数属于特定类型(可能是引用类型)。这也适用于身体中定义的任何lambdas。 Lambda最终会转换为嵌套类中的方法,所以我猜嵌套类也会受到影响(?)。奇怪的是,拥有一个复杂的初始化程序没有任何影响。
性能影响远远高于正常的接口方法调用,并且与虚拟泛型方法调用一样大(来自其他研究)。
这是什么原因?这是我第一次真正被.NET的行为所困扰。我的印象是静态构造函数运行一次,否则效果不大。
代码如下所示。你可以在这里摆弄一个更长的版本:https://dotnetfiddle.net/e15ndG
using System;
using System.Diagnostics;
using System.Threading;
using System.Runtime.CompilerServices;
using System.Linq;
namespace Tests {
//this is used for benchmarks
internal class Bench {
public int Drops = 5;
public int Runs = 10;
public int MsTimeout = 20000;
public Stopwatch Watch = new Stopwatch();
public double InvokeTest(Action act) {
Action runner = () => {
for (int i = 0; i < Drops; i++) {
act();
}
Watch.Reset();
Watch.Start();
for (int i = 0; i < Runs; i++) {
act();
}
Watch.Stop();
};
var thread = new Thread(() => runner());
thread.Start();
var success = thread.Join(MsTimeout);
return success ? Watch.Elapsed.TotalMilliseconds/Runs : -1;
}
}
internal static class GenericObjectStaticConstructor<T>{
static GenericObjectStaticConstructor() {}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void NothingAtAll() {}
public static void SeemsVerySimple(int iterations) {
var z = 0;
for (int i = 0; i < iterations; i++) {
NothingAtAll();
}
}
}
public static class GenericObjectNoStaticConstructor<T>{
private static int DoNothing(int x) {
return x;
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void DoNothingAtAll() {}
public static void SeemsVerySimple(int iterations) {
for (int i = 0; i < iterations; i++) {
DoNothingAtAll();
}
}
}
public class Program {
public static void Main (String[] args) {
var bench = new Bench();
var time1 = bench.InvokeTest(() => GenericObjectStaticConstructor<string>.SeemsVerySimple(1000000));
var time2 = bench.InvokeTest(() => GenericObjectStaticConstructor<int>.SeemsVerySimple(1000000));
var time3 = bench.InvokeTest(() => GenericObjectNoStaticConstructor<string>.SeemsVerySimple(1000000));
var time4 = bench.InvokeTest(() => GenericObjectNoStaticConstructor<int>.SeemsVerySimple(1000000));
Console.WriteLine("Static Constructor<String>: {0}, Static Constructor<int>: {1}, NoConstructor<string>: {2}, NoConstructor<int>: {3}", time1, time2, time3, time4);
}
}
}
答案 0 :(得分:1)