解决方案是使用 LambdaExpression.CompileToMethod(MethodBuilder方法) 代替 LambdaExpression.Compile() 。
我认为Jethro在他假定CAS参与其中时走在了正确的轨道上。在测试中,当我使用表达式树调用未在生成的程序集中动态定义的函数时(即使用Expression.Call调用库方法而不是生成的代码片段),探查器才开始显示对JIT_MethodAccessAllowedBySecurity的调用。表明减速是由CAS检查我生成的代码可以访问它正在调用的方法引起的。似乎通过对我希望调用的函数应用声明性安全性修改,我可以避免这种开销。
不幸的是,通过使用声明性安全性(PermissionSet,SecurityAction.LinkDemand等),我无法摆脱JIT_MethodAccessAllowedBySecurity开销。有一次,我的项目中的每个方法都标有[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倍。感谢大家的帮助,我希望这可以为其他人节省一些时间。
我认为这与CAS(代码访问安全性)有关。
CAS是基于装配的。当你编码 调用受保护的方法.NET 框架运行时检查你的 汇编以查看是否已被授予 一个或多个必要的权限 方法。 .NET Framework rutime 然后走遍堆栈检查每一个 在堆栈中组装这些 ermissions。如果一个组件没有 拥有所有必需的权限, 引发了一个securityexception和 代码运行。
以下是我认为您的代码正在发生的事情。
...发生堆栈行走和政策 每次检查都是预先形成的 方法被调用。这是一个特别的 类中组件的问题 库,可能被称为许多 倍。在这种情况下,你可以使用 链接需求表明 执行权限集检查 在链接时作为JIT的一部分 复杂的过程。要做到这一点,你 使用a来装饰方法 具有的权限属性 值的参数 SecurityAction.LinkDemand 。
SecurityAction.LinkDemand
我希望这有帮助,看起来你需要做的就是设置 SecurityAction.LinkDemand 属性。引用的文本来自Microsoft .NET 2.0开发的高级基础。
问候