Compiled C# Lambda Expressions Performance

前端 未结 4 887
悲哀的现实
悲哀的现实 2020-12-04 05:44

Consider the following simple manipulation over a collection:

static List x = new List() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var result          


        
4条回答
  •  误落风尘
    2020-12-04 06:01

    Recently I asked an almost identical question:

    Performance of compiled-to-delegate Expression

    The solution for me was that I shouldn't call Compile on the Expression, but that I should call CompileToMethod on it and compile the Expression to a static method in a dynamic assembly.

    Like so:

    var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
      new AssemblyName("MyAssembly_" + Guid.NewGuid().ToString("N")), 
      AssemblyBuilderAccess.Run);
    
    var moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");
    
    var typeBuilder = moduleBuilder.DefineType("MyType_" + Guid.NewGuid().ToString("N"), 
      TypeAttributes.Public));
    
    var methodBuilder = typeBuilder.DefineMethod("MyMethod", 
      MethodAttributes.Public | MethodAttributes.Static);
    
    expression.CompileToMethod(methodBuilder);
    
    var resultingType = typeBuilder.CreateType();
    
    var function = Delegate.CreateDelegate(expression.Type,
      resultingType.GetMethod("MyMethod"));
    

    It's not ideal however. I'm not quite certain to which types this applies exactly, but I think that types that are taken as parameters by the delegate, or returned by the delegate have to be public and non-generic. It has to be non-generic because generic types apparently access System.__Canon which is an internal type used by .NET under the hood for generic types and this violates the "has to be a public type rule).

    For those types, you can use the apparently slower Compile. I detect them in the following way:

    private static bool IsPublicType(Type t)
    {
    
      if ((!t.IsPublic && !t.IsNestedPublic) || t.IsGenericType)
      {
        return false;
      }
    
      int lastIndex = t.FullName.LastIndexOf('+');
    
      if (lastIndex > 0)
      {
        var containgTypeName = t.FullName.Substring(0, lastIndex);
    
        var containingType = Type.GetType(containgTypeName + "," + t.Assembly);
    
        if (containingType != null)
        {
          return containingType.IsPublic;
        }
    
        return false;
      }
      else
      {
        return t.IsPublic;
      }
    }
    

    But like I said, this isn't ideal and I would still like to know why compiling a method to a dynamic assembly is sometimes an order of magnitude faster. And I say sometimes because I've also seen cases where an Expression compiled with Compile is just as fast as a normal method. See my question for that.

    Or if someone knows a way to bypass the "no non-public types" constraint with the dynamic assembly, that's welcome as well.

提交回复
热议问题