Static constructors cause a performance overhead?

后端 未结 4 1246
轮回少年
轮回少年 2020-12-29 07:55

Recently read in a article on dotnetpearls.com here saying that static ctors take a substantial amount of perfomance hit.

Could not fathom why?

4条回答
  •  太阳男子
    2020-12-29 08:11

    I just did a small test to check the impact of adding a static constructor to one of my classes.

    I have a base class that looks like this:

    public abstract class Base
    {
        public abstract Task DoStuffAsync();
    }
    

    The problem is, that in one of the implementations that method does nothing, so I can set a pre-made completed task and return it every time.

    public sealed class Test1 : Base
    {
        readonly Task _emptyTask;
    
        public Test1()
        {
            TaskCompletionSource source = new TaskCompletionSource();
            source.SetResult(null);
            _emptyTask = source.Task;
        }
    
        public override Task DoStuffAsync()
        {
            return _emptyTask;
        }
    }
    
    
    

    (Other option is to return the task on demand, but turns out this method is always called)

    Objects of this class are created very very often, usually in loops. Looking at it, it looks like setting _emptyTask as a static field would be beneficial since it would be the same Task for all methods:

    public sealed class Test2 : Base
    {
        static readonly Task _emptyTask;
    
        static Test2()
        {
            TaskCompletionSource source = new TaskCompletionSource();
            source.SetResult(null);
            _emptyTask = source.Task;
        }
    
        public override Task DoStuffAsync()
        {
            return _emptyTask;
        }
    }
    
    
    

    Then I remember the "issue" with static constructors and performance, and after research a little (that is how I get here), I decide to do a small benchmark:

    Stopwatch sw = new Stopwatch();
    List test1list = new List(), test2list = new List();
    
    for (int j = 0; j < 100; j++)
    {
        sw.Start();
        for (int i = 0; i < 1000000; i++)
        {
            Test1 t = new Test1();
            if (!t.DoStuffAsync().IsCompleted)
                throw new Exception();
        }
        sw.Stop();
        test1list.Add(sw.ElapsedMilliseconds);
    
        sw.Reset();
        sw.Start();
        for (int i = 0; i < 1000000; i++)
        {
            Test2 t = new Test2();
            if (!t.DoStuffAsync().IsCompleted)
                throw new Exception();
        }
        sw.Stop();
        test2list.Add(sw.ElapsedMilliseconds);
    
        sw.Reset();
        GC.Collect();
    }
    
    Console.WriteLine("Test 1: " + test1list.Average().ToString() + "ms.");
    Console.WriteLine("Test 2: " + test2list.Average().ToString() + "ms.");
    

    And the results are quite clear:

     Test 1: 53.07 ms. 
     Test 2: 5.03 ms. 
     end
    

    So despite of having a static constructor, the benefit outweighs the issue. So always measure.

    提交回复
    热议问题