6

我正在用 C# 构建一个消息调度映射,并且主要是在使用一些不同的方法。我对我正在测量的性能差异感到好奇,但从 IL 来看,原因并不明显。

消息映射:

delegate void MessageHandler(Message message);
AddHandler(Type t, MessageHandler handler) 
{ 
    /* add 'handler' to messageMap invocation list */ 
}

delegate void GenericMessageHandler<T>(T message);
AddHandler<T>(GenericMessageHandler<T> handler) where T: Message
{
    AddHandler(typeof(T), e => { handler((T)e); });
}

Dictionary<Type, MessageHandler> messageMap;

然后我有一个 Messages 的类层次结构,类似于 WPF 中的 EventArgs,例如:

public class Message {}
public class VelocityUpdateMessage : Message

和具有处理函数的观察者类:

void HandleVelocityUpdate(VelocityUpdateMessage message) { ... }

我正在测量 2 种添加和调用处理程序的方法。我正在包装委托调用,因此我可以获得一些概念类型安全性,这就是性能差异。

方法一:监听器调用

AddHandler(typeof(VelocityUpdateMessage), 
           e => { HandleVelocityUpdate((VelocityUpdateMessage)e); });

方法2:监听器调用

AddHandler<VelocityUpdateMessage>(HandleVelocityUpdate);

这两种方法都构建了一个 MessageHandler 委托,该委托进行强制转换和相同的方法调用,但是调用使用方法 #2 构建的委托有点慢,即使生成的 IL 看起来相同。转换为泛型类型是否有额外的运行时开销?是类型约束吗?一旦解决了泛型类型,我希望 JITted 代表是相同的。

感谢您提供任何信息。

4

2 回答 2

3

下面的行在每次调用时都会创建一个匿名类型的新实例。这可能是您的性能差异的原因吗?

AddHandler(typeof(T), e => { handler((T)e); }); 
于 2012-01-21T08:54:27.273 回答
0

好的,我必须查看 MethodBody.GetILAsByteArray() IL 而不是 ILSpy 结果,以便代表们深入了解这一点。使用通用委托来包装我的消息处理程序并转换消息类型生成:

0000 : ldarg.0
0001 : ldfld
0006 : ldarg.1
0007 : unbox.any
000C : callvirt void MessageTest.Message+tMessageHandler`1[MessageTest.VelocityUpdateMessage].Invoke(‌​MessageTest.VelocityUpdateMessage) 
0011 : ret

具有显式强制转换的包装委托生成:

0000 : ldarg.0
0001 : ldarg.1
0002 : castclass
0007 : call void Message.Component.HandleVelocityUpdate(MessageTest.VelocityUpdateMessage)
000C : ret

所以是的,以这种方式使用泛型的开销最小。

于 2012-01-21T21:25:53.607 回答