动态创建类型:Emit vs Compilation performance

时间:2018-02-12 15:26:39

标签: c# dynamic-compilation

编辑(TLDR),我的问题是: 为什么这两种方法之间存在巨大差距(10倍)

有(我认为)两种动态创建类型的方法:使用Emit,以及运行时的源代码。我想对这两者进行基准测试,我发现从源代码编译的速度要快10倍。这是正常的吗?我觉得我做错了什么。

这里我定义了我创建的类型数量(4000)。

static int limit = 4000;

这是允许我使用CSharpCodeProvider

创建4000种类型的代码
    [TestMethod]
    public void TEST_WITH_COMPILATION()
    {
        System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
        watch.Start();

        StringBuilder builder = new StringBuilder();

        builder.Append("using System;\n");      
        builder.Append("namespace MyDynamicAssembly\n");
        builder.Append("{\n");


        for (int i = 0; i < limit; i++)
        {
            builder.Append(@"   
public class MyType"+i+ @"
{
    public int ID { get; set; }
    public string Name { get; set; }
}");
        }          

        builder.Append("\n}");


        CompilerResults results = new CSharpCodeProvider().CompileAssemblyFromSource(new CompilerParameters
        {
            GenerateInMemory = true,
            GenerateExecutable = false,
        }, builder.ToString());                     

        var types = results.CompiledAssembly.GetTypes();

        System.Diagnostics.Debug.WriteLine(watch.Elapsed, " Compiled");
    }

这是允许我使用Emit

创建4000种类型的代码
    [TestMethod]
    public void TEST_WITH_EMIT()
    {
        System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
        watch.Start();            

        ModuleBuilder moduleBuilder = AppDomain
         .CurrentDomain
         .DefineDynamicAssembly(new AssemblyName("MyDynamicAssembly"), AssemblyBuilderAccess.Run)
         .DefineDynamicModule("MyModule");

        List<Type> types = new List<Type>();

        for (int i=0; i < limit; i++)
        {
            TypeBuilder typeBuilder = moduleBuilder.DefineType("MyType" + i, TypeAttributes.Public);
            typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);               
            CreateAutoImplementedProperty(typeBuilder, "ID", typeof(int));
            CreateAutoImplementedProperty(typeBuilder, "Name", typeof(string));
            types.Add(typeBuilder.CreateType());
        }

        System.Diagnostics.Debug.WriteLine(watch.Elapsed, " Emitted");       

    }      

CreateAutoImplementedProperty的源代码:

    public static void CreateAutoImplementedProperty(TypeBuilder builder, string propertyName, Type propertyType)
    {
        const string PrivateFieldPrefix = "m_";
        const string GetterPrefix = "get_";
        const string SetterPrefix = "set_";

        FieldBuilder fieldBuilder = builder.DefineField(
            string.Concat(PrivateFieldPrefix, propertyName),
                          propertyType, FieldAttributes.Private);

        PropertyBuilder propertyBuilder = builder.DefineProperty(
            propertyName, PropertyAttributes.HasDefault, propertyType, null);

        MethodAttributes propertyMethodAttributes =
            MethodAttributes.Public | MethodAttributes.SpecialName |
            MethodAttributes.HideBySig;

        MethodBuilder getterMethod = builder.DefineMethod(
            string.Concat(GetterPrefix, propertyName),
            propertyMethodAttributes, propertyType, Type.EmptyTypes);

        ILGenerator getterILCode = getterMethod.GetILGenerator();
        getterILCode.Emit(OpCodes.Ldarg_0);
        getterILCode.Emit(OpCodes.Ldfld, fieldBuilder);
        getterILCode.Emit(OpCodes.Ret);

        MethodBuilder setterMethod = builder.DefineMethod(
            string.Concat(SetterPrefix, propertyName),
            propertyMethodAttributes, null, new Type[] { propertyType });

        ILGenerator setterILCode = setterMethod.GetILGenerator();
        setterILCode.Emit(OpCodes.Ldarg_0);
        setterILCode.Emit(OpCodes.Ldarg_1);
        setterILCode.Emit(OpCodes.Stfld, fieldBuilder);
        setterILCode.Emit(OpCodes.Ret);

        propertyBuilder.SetGetMethod(getterMethod);
        propertyBuilder.SetSetMethod(setterMethod);
    }

结果如下:

  • 编译:00:00:00.8716579
  • 发出:00:00:09.6288015

如何解释性能差距?

0 个答案:

没有答案