Решение состоит в том, чтобы использовать LambdaExpression.CompileToMethod (метод MethodBuilder) вместо LambdaExpression.Compile () .
Я думаю, что Джетро был на правильном пути, когда утверждал, что CAS был замешан. В ходе тестирования профилировщик начал показывать вызовы JIT_MethodAccessAllowedBySecurity, когда я использовал деревья выражений для вызова функций, которые не были определены динамически в сгенерированной сборке (т. Е. С помощью Expression.Call для вызова метода библиотеки, а не фрагмента сгенерированного кода). предполагает, что замедление было вызвано проверкой CAS, что мой сгенерированный код имел доступ к методам, которые он вызывал. Из этого следует, что, применяя декларативные модификации безопасности к функциям, которые я хотел вызвать, я мог бы избежать этих издержек.
К сожалению, я не смог избавиться от издержек JIT_MethodAccessAllowedBySecurity при любом использовании декларативной безопасности (PermissionSet, SecurityAction.LinkDemand и тому подобное). В какой-то момент у меня был буквально каждый метод в моем проекте, помеченный [PermissionSet (SecurityAction.LinkDemand, Unrestricted = true)], без результатов.
К счастью, когда я искал способы добавить атрибуты к сгенерированным делегатам, я наткнулся на решение - используя MethodBuilder для компиляции дерева выражений, а не встроенный метод LambdaExpression.Compile.
Я включил фрагмент кода, который заменил .Compile () и привел к устранению вызовов JIT_MethodAccessAllowedBySecurity и ускорению> 2x в нашем механизме вычислений:
// T must be of delegate type (Func<T>, Func<T1, T2>, etc.)
public static T GetCompiledDelegate<T>(Expression<T> expr)
{
var assemblyName = new AssemblyName("DelegateHostAssembly") { Version = new Version("1.0.0.0") };
var assemblyBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(
assemblyName,
AssemblyBuilderAccess.RunAndSave);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("DelegateHostAssembly", "DelegateHostAssembly.dll");
var typeBuilder = moduleBuilder.DefineType("DelegateHostAssembly." + "foo", TypeAttributes.Public);
var methBldr = typeBuilder.DefineMethod("Execute", MethodAttributes.Public | MethodAttributes.Static);
expr.CompileToMethod(methBldr);
Type myType = typeBuilder.CreateType();
var mi = myType.GetMethod("Execute");
// have to box to object because .NET doesn't allow Delegates as generic constraints,
// nor does it allow casting of Delegates to generic type variables like "T"
object foo = Delegate.CreateDelegate(typeof(T), mi);
return (T)foo;
}
Этот код последовательно> в 2 раза быстрее при использовании любого кода, который использует деревья выражений для вызова функций, которые сами не определены деревьями выражений. Спасибо всем за помощь, и я надеюсь, что это сэкономит кому-то еще несколько циклов.