6

我即将在服务器应用程序上编写一组方法,这些方法接收从 TCP 套接字接收的消息,对它们进行编码/解码,然后对它们进行加密/解密。

考虑到消息被定义为特殊类型,每个都有自己的一组属性和总长度,我需要选择以下解决方案之一: 1. 制作使用泛型的方法,例如Encode<T>(...) where T : IMessage,然后为每种类型实现编码器/解码器message 并ResolveEncoder<T>让它为想要的消息选择编码器,或者 2. 创建使用任何类型消息的方法,只要它实现IMessage,例如Encode(IMessage message),并使用 System.Reflection 来确定我需要了解的所有信息。

我对解决方案#2 更感兴趣,因为它使我的代码小了 30 倍。但是,我担心属性的不断反射是否会影响性能。现在由于我完成项目的时间有限,我不能真正“实验”。

对于任何一种解决方案的性能如何下降的任何个人经验或与基准的链接,我将不胜感激。

4

6 回答 6

6

现在由于我完成项目的时间有限,我不能真正“实验”。

那么你真正的限制不是性能,而是你可以在给定的时间限制内编码、测试和调试。假设您声称反射版本小 30 倍,听起来这就是您应该倾向于的。

但是,有五点:

  1. 我怀疑 30 倍是正确的估计,它可能要小得多。
  2. 反射的性能将低于使用泛型。毫无疑问。
  3. “但是,我担心属性的不断反射是否会影响性能。” 您可以通过积极缓存PropertyInfos 以及您通过反射加载的内容来缓解其中的一些问题。
  4. 您可以使用表达式树执行类似于反射的操作,并且您会看到这样做会显着提升性能。这是一篇文,将在此问题上将您推向正确的方向。但是,如果您还不熟悉使用表达式树,考虑到您的时间限制,使用您不熟悉的概念进行编码、测试和调试是有风险的。
  5. 您确定这甚至是性能瓶颈吗?如果网络延迟在这里占主导地位,并且您过早地进行优化,我不会感到震惊。
于 2012-04-18T03:38:14.840 回答
4

反射可以足够快。但需要正确执行。

反射性能 -

快速和轻便的功能

typeof
Object.GetType
typeof == Object.GetType
Type equivalence APIs (including typehandle operator overloads)
get_Module
get_MemberType
Some of the IsXX predicate APIs
New token/handle resolution APIs in the .NET Framework 2.0

昂贵的功能

GetXX  APIs (MethodInfo, PropertyInfo, FieldInfo, and so on)
GetCustomAttributes
Type.InvokeMember
Invoke APIs (MethodInfo.Invoke, FieldInfo.GetValue, and so on)
get_Name (Name property)
Activator.CreateInstance

来源 - 避开常见的性能陷阱以打造快速的应用程序

MethodInfo 可以加速 -提高性能反射,我应该考虑哪些替代方案

好的链接:
.NET 反射的成本是多少?
http://www.codeproject.com/Articles/18450/HyperDescriptor-Accelerated-dynamic-property-acces

于 2012-04-18T03:55:15.703 回答
0

泛型在编译时绑定,并且与普通类型一样高效。反思将付出巨大的代价。

于 2012-04-18T03:35:06.170 回答
0

如果您关心性能,请考虑为每种类型的消息生成DynamicMethod 。将生成动态方法的代码对于所有消息类型都是相同的(就像使用反射一样),但是一旦生成动态方法,您将不会受到反射的性能影响。缺点是代码更难编写,更难调试,所以如果你有时间压力,这可能不是最好的选择。

于 2012-04-18T04:19:53.247 回答
0

通常有用的一种方法是将反射与静态泛型类一起使用。这是诸如EqualityComparer<T>.Default. 本质上,对于任何特定类型T,第一个引用EqualityComparer<T>.Default将不得不使用反射来确定类型是否T实现IComparable<T>并构造一个IEqualityComparer<T>在不受约束的T和使用上运行的实现,或者是对和使用的Object.Equals约束。为此目的使用反射有点慢,但对于任何特定类型只需要执行一次。一旦构造了实现,它将被存储在一个静态字段中TIEqualityComparer<T>IEqualityComparer<T>.EqualsTEqualityComparer<T>,因此任何将来获取该类型的默认比较器的请求都将能够简单地使用早期构造的IEqualityComparer<T>实现。

这种方法结合了泛型的速度和灵活性来完成仅使用泛型还不够的事情。

于 2012-04-18T17:36:46.157 回答
0

当前代码执行此操作:

protected void Decode<T>(Action<BinaryReader> action, byte[] buffer) {...}

创建 MemoryStream 流。在流上创建 BinaryReader 阅读器。然后执行动作(阅读器)。

现在假设我们有 HelloMessage.cs,它只有两个属性,一个字节 Id 和一个 int 描述符。解码器类 HelloMessageCodec.cs 的 Decode 方法如下所示:

public HelloMessage Decode(byte[] buffer)
{
    var message = new HelloMessage();
    Decode<HelloMessage>(reader => 
        { message.Id = reader.ReadByte();
          message.Descriptor = reader.ReadInt32();
        }, buffer);
    return message;
}

这确实做得很好,但是,大约有 15 种类型的消息,并且每种类型都有自己的 xxxMessageCodec.cs,带有 Decode 和 Encode 实现,每个都有在 Action 委托中手动传递的属性。

现在我必须进行加密,这意味着,如果我遵循这种模式,我必须构建 15 个不同的消息加密器。

我已经将所有编解码器代码重新设计为解决方案#2(带有反射),而不是拥有 15 x 2 个函数,我只有 2 个函数 + 没有底层级别,只有两个函数通过它们的属性处理消息并调用 ReadByte、ReadInt32、 ...取决于 typeof 属性。

所以,我已经完成了这项工作,但是我没有足够的时间来测试性能,因为我必须继续进行加密工作。我必须选择两种解决方案中的一种来继续进行,并且我有睡眠问题,较小的解决方案(反射解决方案)是否会在稍后将我踢回来:)

于 2012-04-19T05:15:59.027 回答