Class 创建性能大比拼(反射,泛型反射,泛型创建,缓存Emit,非缓存Emit)

  一说到反射,很多人都想到了性能,更有甚者直接说“慎用反射,遗患无穷”,“用反射,感觉怎么像是退步啊~”,看到这种言论,直接把反射妖魔化了,如果这种言论长此以往,势必会对很多对反射初学者造成负面影响。反射是一把双刃剑,看你怎样使用了,下面我就用代码说话。

class TestEntity { }

  1. 手工创建TestEntity 

[TestInfo(Category = "Class.Constructor", Name = "Direct")]
class DirectInvokeMode:IRunable
{
public void Run()
{
new TestEntity();
}
}

     2. 反射创建TestEntity 

[TestInfo(Category = "Class.Constructor", Name = "Reflect")]
class ReflectInvokeMode : IRunable
{
public void Run()
{
Activator.CreateInstance(
typeof(TestEntity));
}
}

  3. 泛型反射创建TestEntity

[TestInfo(Category = "Class.Constructor", Name = "GenericReflect")]
class GenericReflectInvokeMode : IRunable
{
public void Run()
{
Activator.CreateInstance
<TestEntity>();
}
}

  4. Generic 直接创建

[TestInfo(Category = "Class.Constructor", Name = "Generic Create")]
class GenericCreateInvokeMode : IRunable
{
public void Run()
{
Create
<TestEntity>();
}

static T Create<T>() where T : new()
{
return new T();
}
}
5. Emit创建
[TestInfo(Category = "Class.Constructor", Name = "Emit")]
class EmitInvokeMode : IRunable
{
static readonly ConstructorHandler Ctor = typeof(TestEntity).GetConstructor(Type.EmptyTypes).GetCreator();

public void Run()
{
Ctor();
}
}

  6. 不缓存Emit的创建

[TestInfo(Category = "Class.Constructor", Name = "NoCacheEmit")]
class NoCacheEmitInvokeMode : IRunable
{
public void Run()
{
typeof(TestEntity).GetConstructor(Type.EmptyTypes).GetCreator()();
}
}

  测试程序:(执行10万次创建Class对象)

foreach (var item in Mappers)
CodeTimer.Time(item.Metadata.Category
+ "->" + item.Metadata.Name, 100000, () => item.Value.Run());

输出结果:

------ Test started: Assembly: NLite.Test.dll ------


Class.Constructor
->Direct
Time Elapsed: 5ms
CPU Cycles:
0
Gen
0: 1
Gen
1: 0
Gen
2: 0

Class.Constructor
->Reflect
Time Elapsed: 320ms
CPU Cycles:
2,968,750
Gen
0: 1
Gen
1: 0
Gen
2: 0

Class.Constructor
->GenericReflect
Time Elapsed: 147ms
CPU Cycles:
1,250,000
Gen
0: 1
Gen
1: 0
Gen
2: 0

Class.Constructor
->Generic Create
Time Elapsed: 159ms
CPU Cycles:
1,406,250
Gen
0: 1
Gen
1: 0
Gen
2: 0

Class.Constructor
->Emit
Time Elapsed: 6ms
CPU Cycles:
0
Gen
0: 2
Gen
1: 0
Gen
2: 0

Class.Constructor
->NoCacheEmit
Time Elapsed:
12,786ms
CPU Cycles:
119,218,750
Gen
0: 162
Gen
1: 81
Gen
2: 0

1 passed, 0 failed, 0 skipped, took 67.77 seconds (NUnit 2.5.5).

  性能比较结果应该是一目了然了!

      附上源代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using System.Reflection;
using NLite.Reflection;

namespace NLite.Test.Reflection
{
    [Contract]
    public interface IRunable
    {
        void Run();
    }

    //测试器元数据
    public interface ITestInfo
    {
        //目录
        string Category { get; }
        //名称
        string Name { get; }
    }

    //映射器元数据注解
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    [MetadataAttributeAttribute]
    public class TestInfoAttribute : ComponentAttribute
    {
        public string Category { get; set; }
        public string Name { get; set; }
    }


    [TestFixture]
    public class SpecBase
    {
        public SpecBase()
        {
        }

        [SetUp]
        public void SetUp()
        {
            Given();
            When();
        }

        public virtual void Given() { }
        public virtual void When()
        {
        }

        [Test]
        public void Test()
        {
            
        }
    }

    public abstract class PerformanceSpecBase : SpecBase
    {
        [InjectMany]
        protected Lazy<IRunable, ITestInfo>[] Mappers;

        protected abstract void RegisterComponents();

        public virtual int Times
        {
            get { return 100000; }
        }

        public override void Given()
        {
            RegisterComponents();
            ServiceRegistry.Compose(this);
        }


        public override void When()
        {
            for (int i = 0; i < 3; i++)
            {
                foreach (var item in Mappers)
                    CodeTimer.Time(item.Metadata.Category + "->" + item.Metadata.Name, Times, () => item.Value.Run());
            }
        }
    }

    public class InvokeConstructorPerformanceSpec : PerformanceSpecBase
    {
        class TestEntity { }

        protected override void RegisterComponents()
        {
            ServiceRegistry
                .Register<DirectInvokeMode>()
                .Register<ReflectInvokeMode>()
                .Register<GenericReflectInvokeMode>()
                .Register <GenericCreateInvokeMode>()
                .Register<EmitInvokeMode>()
                .Register < NoCacheEmitInvokeMode>()
                .Register < GenericReflectInvokeMode2>()
                ;
        }
        [TestInfo(Category = "Class.Constructor", Name = "Direct")]
        class DirectInvokeMode:IRunable
        {
            public void Run()
            {
                new TestEntity();
            }
        }

        [TestInfo(Category = "Class.Constructor", Name = "Reflect")]
        class ReflectInvokeMode : IRunable
        {
            public void Run()
            {
                Activator.CreateInstance(typeof(TestEntity));
            }
        }

        [TestInfo(Category = "Class.Constructor", Name = "GenericReflect")]
        class GenericReflectInvokeMode : IRunable
        {
            public void Run()
            {
                Activator.CreateInstance<TestEntity>();
            }
        }

        [TestInfo(Category = "Class.Constructor", Name = "Reflect->Reflect")]
        class GenericReflectInvokeMode2 : IRunable
        {
            static readonly MethodInfo CreateMethod = typeof(Activator)
                .GetMethod("CreateInstance", Type.EmptyTypes)
                .MakeGenericMethod(typeof(TestEntity));

            public void Run()
            {
                CreateMethod.Invoke(null,null);
            }


        }

        

        [TestInfo(Category = "Class.Constructor", Name = "Generic Create")]
        class GenericCreateInvokeMode : IRunable
        {
            public void Run()
            {
                Create<TestEntity>();
            }

            static T Create<T>() where T : new()
            {
                return new T();
            }
        }

        [TestInfo(Category = "Class.Constructor", Name = "Emit")]
        class EmitInvokeMode : IRunable
        {
            static readonly ConstructorHandler Ctor = typeof(TestEntity).GetConstructor(Type.EmptyTypes).GetCreator();

            public void Run()
            {
                Ctor();
            }
        }


        [TestInfo(Category = "Class.Constructor", Name = "NoCacheEmit")]
        class NoCacheEmitInvokeMode : IRunable
        {
            public void Run()
            {
                typeof(TestEntity).GetConstructor(Type.EmptyTypes).GetCreator()();
            }
        }


    }

   
}

      最后给大家一个思考题:Struct 创建性能大比拼的结果是怎样的?(注意Struct是值类型,Class是引用类型,值类型是分配在栈上的,引用类型是分配在堆上的)

posted @ 2011-04-18 16:37  风云  阅读(4225)  评论(24编辑  收藏  举报