当前位置: 首页 > 编程语言 > C#

在muticast委托上使用慢速DynamicInvoke的替代方法分享

时间:2023-04-10 12:44:38 C#

C#学习教程:在多播委托上使用慢速DynamicInvoke的替代方法(d!=null){//检查每个调用目标foreach(DelegatedDelgateind.GetInvocationList()){if(dDelgate.Target!=null&&dDelgate.TargetisSystem.ComponentModel.ISynchronizeInvoke&&((System.ComponentModel.ISynchronizeInvoke)(dDelgate.Target)).InvokeRequired){//如果target是ISynchronizeInvoke,需要Invoke,通过ISynchronizeInvoke调用((System.ComponentModel.ISynchronizeInvoke)(dDelgate.Target)).Invoke(dDelgate,newobject[]{发件人,参数});}else{//否则动态调用dDelgate.DynamicInvoke(sender,param);}}}}此代码示例负责调用事件,表示为多播委托,其中调用目标包括Don'tcareaboutISynchronizeInvokeacrossthreads和classesthatimplementISynchronizeInvokeandfocusoncross-threads,例如WindowsForms控件.理论上,这段代码工作得很好,没有发生错误。但是DynamicInvoke很慢,并不是说它是目前应用的瓶颈。所以,我的问题是:有没有办法在不破坏直接订阅事件的功能的情况下加速这个小功能?所有事件/委托的签名是(objectsender,EventArgsparam)如果dDelegate是已知类型(即Action),您可以随时强制转换并直接调用它。话虽如此,如果您使用的是.NET3.5,则可以使用表达式树进行一些优化。我的示例使用.NET4中的并发字典,但也可以改用普通字典和锁。想法如下:委托持有它调用的方法。对于调用的每个唯一方法,我创建(使用表达式树)调用该特定方法的已编译委托。创建一个编译委托是昂贵的,这就是为什么缓存它很重要,但是一旦创建一个编译委托就和普通委托一样快。在我的机器上,3,000,000次调用使用编译委托需要1秒,使用DynamicInvoke需要16秒。//注释此行以使用DynamicInvoke作为比较#defineUSE_FAST_INVOKEnamespaceDynInvoke{usingSystem;使用System.Collections.Concurrent;使用System.Linq.Expressions;使用System.Reflection;staticclassProgram{delegatevoidCachedMethodDelegate(objectinstance,objectsender,EventArgsparam);只读静态ConcurrentDictionarys_cachedMethods=newConcurrentDictionary();publicstaticvoidInvokeExternal(Delegated,objectsender,EventArgsparam){if(d!=null){//检查每个调用目标foreach(vardDelgateind.GetInvocationList()){if(dDelgate.Target!=null&&dDelgate.TargetisSystem.ComponentModel.ISynchronizeInvoke&&((System.ComponentModel.ISynchronizeInvoke)(dDelgate.Target)).InvokeRequired){//如果target是ISynchronizeInvoke并且需要Invoke,通过ISynchronizeInvoke调用((System.ComponentModel.ISynchronizeInvoke)(dDelgate.Target)).Invoke(dDelgate,newobject[]{发件人,参数});}else{#ifUSE_FAST_INVOKEvarmethodInfo=dDelgate.Method;vardel=s_cachedMethods.GetOrAdd(methodInfo,CreateDelegate);del(dDelgate.Target,sender,param);#elsedDelgate.DynamicInvoke(发件人,参数);#endif}}}}staticCachedMethodDelegateCreateDelegate(MethodInfomethodInfo){varinstance=Expression.Parameter(typeof(object),"instance");varsender=Expression.Parameter(typeof(object),"sender");varparameter=Expression.Parameter(typeof(EventArgs),"参数");varlambda=Expression.Lambda(Expression.Call(Expression.Convert(instance,methodInfo.DeclaringType),methodInfo,sender,parameter),instance,sender,parameter);返回lambda.Compile();}classMyEventListener{publicintCount;publicvoidReceive(objectsender,EventArgsparam){++Count;}}classMyEventSource{公共事件ActionAnEvent;publicvoidInvokeAnEvent(EventArgsarg2){InvokeExternal(AnEvent,this,arg2);}}staticvoidMain(string[]args){vareventListener=newMyEventListener();vareventSource=newMyEventSource();eventSource.AnEvent+=eventListener.Receive;vareventArgs=newEventArgs();eventSource.InvokeAnEvent)(eventArgs;constintCount=3000000;varthen=DateTime.Now;for(variter=0;iter编辑:由于OP使用.NET2,我添加了一个应该与.NET2运行时兼容的示例(因为我使用的是VS2010,所以我可能会错误地使用一些新的语言功能,但我确实使用.NET2运行时进行编译)//注释此行以使用DynamicInvoke作为比较#defineUSE_FASTER_INVOKEnamespaceDynInvoke{usingSystem;使用System.Globalization;使用System.Reflection.Emit;使用System.Collections.Generic;使用System.ComponentModel;使用System.Reflection;staticclassFasterInvoke{delegatevoidCachedMethodDelegate(objectinstance,objectsender,EventArgsparam);只读静态字典s_cachedMethods=newDictionary();publicstaticvoidInvokeExternal(Delegated,objectsender,EventArgsparam){if(d!=null){Delegate[]invocationList=d.GetInvocationList();foreach(调用列表中的委托子委托){objecttarget=subDelegate.Target;if(target!=null&&targetisISynchronizeInvoke&&((ISynchronizeInvoke)target).InvokeRequired){((ISynchronizeInvoke)target).Invoke(subDelegate,new[]{sender,param});}}else{#ifUSE_FASTER_INVOKEMethodInfomethodInfo=subDelegate.Method;缓存dMethodDelegate缓存方法委托;布尔结果;锁(s_cachedMethods){结果=s_cachedMethods.TryGetValue(methodInfo,outcachedMethodDelegate);}if(!result){cachedMethodDelegate=CreateDelegate(methodInfo);锁(s_cachedMethods){s_cachedMethods[methodInfo]=cachedMethodDelegate;}}cachedMethodDelegate(目标、发送者、参数);#elsesubDelegate.DynamicInvoke(发件人,参数);#endif}}}}staticCachedMethodDelegateCreateDelegate(MethodInfomethodInfo){if(!methodInfo.DeclaringType.IsClass){throwCreateArgumentExceptionForMethodInfo(methodInfo,"声明类型必须是方法的类:{0}.{1}");}if(methodInfo.ReturnType!=typeof(void)){throwCreateArgumentExceptionForMethodInfo(methodInfo,"方法必须返回void:{0}.{1}");}ParameterInfo[]parameters=methodInfo.GetParameters();if(parameters.Length!=2){throwCreateArgumentExceptionForMethodInfo(methodInfo,"方法必须正好有两个参数ters:{0}.{1}");}if(parameters[0].ParameterType!=typeof(object)){throwCreateArgumentExceptionForMethodInfo(methodInfo,"方法第一个参数必须是对象类型:{0}.{1}");}TypesecondParameterType=parameters[1].ParameterType;if(!typeof(EventArgs).IsAssignableFrom(secondParameterType)){throwCreateArgumentExceptionForMethodInfo(methodInfo,"方法第二个参数必须可分配给EventArgs类型的变量:{0}.{1}");}//下面等同于这样的方法(如果这在C#中是可表达的)://voidInvoke(objectinstance,objectsender,EventArgsargs)//{//(()instance).(//sender,//()args//);//}DynamicMethoddynamicMethod=newDynamicMethod(String.Format(CultureInfo.InvariantCulture,"Run_{0}_{1}",methodInfo.DeclaringType.Name,methodInfo.Name),null,new[]{typeof(object),typeof(object),typeof(EventArgs)},true);ILGeneratorilGenerator=dynamicMethod.GetILGenerator();ilGenerator.Emit(OpCodes.Ldarg_0);ilGenerator.Emit(OpCodes.Castclass,methodInfo.DeclaringType);ilGenerator.Emit(OpCodes.Ldarg_1);ilGenerator.Emit(OpCodes.Ldarg_2);ilGenerator.Emit(OpCodes.Isinst,secondParameterType);如果(methodInfo.IsVirtual){ilGenerator.EmitCall(OpCodes.Callvirt,methodInfo,null);}else{ilGenerator.EmitCall(OpCodes.Call,methodInfo,null);}ilGenerator.Emit(OpCodes.Ret);返回(CachedMethodDelegate)dynamicMethod.CreateDelegate(typeof(CachedMethodDelegate));}staticExceptionCreateArgumentExceptionForMethodInfo(MethodInfomethodInfo,字符串消息){returnnewArgumentException(String.Format(CultureInfo.InvariantCulture,消息,methodInfo.DeclaringType.FullName,methodInfo.Name),“methodInfo”);}}staticclassProgram{classMyEventArgs:EventArgs{}classMyEventListener{publicintCount;publicvoidReceive(objectsender,MyEventArgsparam){++Count;}}委托voidMyEventHandler(object发件人,MyEventArgsargs);类MyEventSource{公共事件MyEventHandlerAnEvent;publicvoidInvokeAnEvent(MyEventArgsarg2){FasterInvoke.InvokeExternal(AnEvent,this,arg2);我的事件监听器();MyEventSourceeventSource=newMyEventSource();eventSource.AnEvent+=eventListener.Receive;MyEventArgseventArgs=newMyEventArgs();eventSource.InvokeAnEvent(eventArgs);(intiter=0;iter如果你有一组已知的类型,你可以先检查它们,如果类型在编译时不知道就返回DynamicInvoke//委托最有可能是EventHandlervare1=dDelegateasEventHandler;如果(e1!=null)e1(发件人,参数);else{//可能是DelegateType2vard2=dDelegateasDelegateType2;如果(d2!=null)d2(发件人,参数);else{//试试DelegateType3vard3=dDelegateasDelegateType3;如果(d3!=null)d3(发件人,参数);else//最后的手段dDelgate.DynamicInvoke(sender,param);}}查看我的图书馆FastDelegate.Net。它在构造中具有codegen并且具有匹配的性能。以上就是C#学习教程的全部内容:在多播委托上使用慢DynamicInvoke的替代方法。如果对大家有用,需要进一步了解C#学习教程,希望大家多多关注---本文来自网络收藏,不代表立场,如涉及侵权,请点击右边联系管理员删除。如需转载请注明出处: