Expression.Compile和Lambda的性能,直接和虚调用直接方法调用和虚方法调用的性能如何(伪代码):varfoo=newFoo();variFoo=(IFoo)foo;foo.Bar();iFoo.Bar();(()=>foo.Bar())();(()=>iFoo.Bar())();表达式.编译(foo,Foo.Bar)();表达式.编译(iFoo,IFoo.Bar)();表达式.CompileToMethod(foo,Foo.Bar);Expression.CompileToMethod(iFoo,IFoo.Bar);MethodInfo.Invoke(foo,Foo.Bar);MethodInfo.Invoke(iFoo,IFoo.Bar);我没有找到任何答案,所以使用System.Diagnostics;使用System.Linq.Expressions;使用System.Reflection;使用System.Reflection.Emit;命名空间ExpressionTest{公共接口IFoo{intBar();}publicsealedclassFooImpl:IFoo{publicintBar(){return0;}}classProgram{staticvoidMain(string[]args){varfoo=newFooImpl();variFoo=(IFoo)foo;FuncdirectLambda=()=>foo.Bar();FuncvirtualLambda=()=>ifFoo.Bar();varcompiledDirectCall=CompileBar(foo,asInterfaceCall:false);varcompiledVirtualCall=CompileBar(foo,asInterfaceCall:true);varcompiledArgDirectCall=CompileBar();varcompiledArgVirtualCall=CompileBar();varbarMethodInfo=typeof(FooImpl).GetMethod(nameof(FooImpl.Bar));variBarMethodInfo=typeof(IFoo).GetMethod(nameof(IFoo.Bar));varcompiledToModuleDirect=CompileToModule();varcompiledToModuleVirtual=CompileToModule();var迭代计数=200000000;Console.WriteLine($"迭代次数:{iterationCount:N0}");varsw=Stopwatch.StartNew();for(inti=0;i)Expression.Compile():{elapsedMs}ms");sw.Restart();for(inti=0;i)Expression.Compile():{elapsedMs}ms");sw.重启();for(inti=0;i)Expression.Compile():{elapsedMs}ms");sw.Restart();for(inti=0;i)Expression.Compile():{elapsedMs}ms");sw.重启();对于(inti=0;i)Expression.CompileToMethod():{elapsedMs}ms");sw.Restart();for(inti=0;i)Expression.CompileToMethod():{elapsedMs}ms");sw.Restart();for(inti=0;iIFoo.Bar():{elapsedMs}ms");sw.重启();for(inti=0;iFooImpl.Bar():{elapsedMs}ms");sw.Restart();for(inti=0;iCompileBar(IFoofoo,boolasInterfaceCall){varfooType=asInterfaceCall?typeof(IFoo):foo.GetType();varmethodInfo=fooType.GetMethod(nameof(IFoo.Bar));varinstance=Expression.Constant(foo,fooType);varcall=Expression.Call(instance,methodInfo);varlambda=Expression.Lambda(call);varcompiledFunction=(Func)lambda.Compile();returncompiledFunction;}staticFuncCompileBar(){varfooType=typeof(TInput);varmethodInfo=fooType.GetMethod(nameof(IFoo.栏));varinstance=Expression.Parameter(fooType,"foo");varcall=Expression.Call(instance,methodInfo);varlambda=Expression.Lambda(call,instance);varcompiledFunction=(Func)lambda.Compile();returncompiledFunction;}staticFuncCompileToModule(){varfooType=typeof(TInput);varmethodInfo=fooType.GetMethod(nameof(IFoo.Bar));varinstance=Expression.Parameter(fooType,"foo");varcall=Expression.Call(instance,methodInfo);varlambda=Expression.Lambda(call,instance);varasmName=newAssemblyName(fooType.Name);varasmBuilder=AssemblyBuilder.DefineDynamicAssembly(asmName,AssemblyBuilderAccess.Run);varmoduleBuilder=asmBuilder.DefineDynamicModule(fooType.Name);vartypeBuilder=moduleBuilder.DefineType(fooType.Name,TypeAttributes.Public);varmethodBuilder=typeBuilder.DefineMethod(nameof(IFoo.Bar),MethodAttributes.Static,typeof(int),new[]{fooType});表达式.Lambda(lambda).CompileToMethod(methodBuilder);varcreatedType=typeBuilder.CreateType();varmi=createdType.GetMethods(BindingFlags.NonPublic|BindingFlags.Static)[1];varfunc=Delegate.CreateDelegate(typeof(Func),mi);返回(函数)函数;在我的笔记本电脑上(发布模式,64位,.NET4.5.2),生成:Iterationcount:200,000,000虚拟MethodInfo.Invoke(FooImpl,Bar):61811msDirectMethodInfo.Invoke(IFoo,Bar):37078msVirtual(Func)Expression.Compile():2894msDirect(Func)Expression.Compile():2242msVirtual(功能)表达式。编译():2319毫秒直接(Func)表达式。编译():2051毫秒虚拟(Func)表达式。CompileToMethod():996毫秒直接(Func)表达式。CompileToMethod():679毫秒Virtual()=>IFoo.Bar():796msDirect()=>FooImpl.Bar():469msVirtualIFoo.Bar():531msDirectFoo.Bar():68ms希望这有帮助,我们可以将问题分为2种情况:.NET4.5.2和ExpressionTest.exe在发布模式下优化(默认发布设置):编译虚拟调用:4625毫秒编译直接调用:3361毫秒Lambda虚拟调用:1096msLambdaDirectCall:576msVirtualCall:649msDirectCall:144ms我们看到“DirectCall”比“VirtualCall”快4.5倍。但正如我们在上面看到的,根本没有电话。Bar方法是内联的。ExpressionTest.exe处于未优化的发布模式.NET4.5.2:编译虚拟调用:5394毫秒编译直接调用:4666毫秒Lambda虚拟调用:1800毫秒Lambda直接调用:1683毫秒虚拟调用:1154毫秒直接调用:1112毫秒因此,“DirectCall”比“VirtualCall”快3-4%。类似问题:Performanceof"direct"virtualcallvsinterfacecallinC#提示:在release模式下,"directcall"情况下完全没有调用。CPU只能从00B531BC(moveax…)到00B531C8(jl00B531BC)。以上就是C#学习教程:Expression.Compile和Lambda的表现,以及虚调用直接分享的所有内容。如果对大家有用,需要进一步了解C#学习教程,希望大家多加关注——for(inti=0;i本文收集自网络,不代表立场,如涉及侵权请点击维权联系管理员删除如有转载请注明出处:
