在泛型类中涉及静态构造函数的非常奇怪的行为

时间:2015-04-05 11:34:19

标签: c# class generics constructor static

我在执行各种常见操作(如装箱,投射,对象分配等)的微观基准测试时偶然发现了这种非常奇怪的行为,以便更好地学习如何实现我一直在努力的数据结构库。

基本上,在泛型类中使用静态构造函数(即使它是空的)会导致任何方法调用都非常慢,但前提是类型参数属于特定类型(可能是引用类型)。这也适用于身体中定义的任何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);
        }

    }
}

1 个答案:

答案 0 :(得分:1)

.NET努力工作,为实现程序员提供顺畅的体验而做了很多事情。

以下是对性能影响的一个很好的解释:

  

https://stackoverflow.com/a/2922740/2129382