System.Reflection vs Generics - performance

I am going to write a set of methods in a server application that receives messages received from a TCP socket, encodes / decodes them and encrypts / decrypts them.

Consideration of messages is defined as special types, each with its own set of properties and total length, I need to choose one of the following solutions: 1. Create methods that use generics, for example Encode<T>(...) where T : IMessage , and then implement an encoder / decoder for each type of message and have a ResolveEncoder<T> that will select the encoder for the desired message or 2. Create a method that uses any type of message if it implements IMessage , for example Encode(IMessage message) , and use System. Reflection to determine everything I need to know about this one.

I'm more interested in solution # 2, as my code is 30 times smaller. However, I am worried if the constant reflection of properties will affect performance. Now, when I finish the project, I can not "experiment".

I would appreciate any personal impressions or benchmarked links on how performance falls with any of the solutions.

+6
source share
6 answers

Reflection can be quite fast. But you need to implement it correctly.

Reflection Efficiency -

Fast and light functions

 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 

Costly features

 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 

Source - Dodge Common Performance Pitfalls for creating fast applications

MethodInfo Can Accelerate - Improving performance reflection, which alternatives should be considered

Good links:
How expensive is .NET reflection? http://www.codeproject.com/Articles/18450/HyperDescriptor-Accelerated-dynamic-property-acces

+4
source

Now, when I finish the project, I can not "experiment".

Then your real limit is not performance, but rather that you can code, test, and debug in a given time limit. Suppose your claim that the reflection version is 30 times smaller seems like you should be leaning.

However, five points:

  • I doubt that 30x is the correct estimate, it is probably much smaller.
  • Reflection will be less effective than using generics. There are no questions about this.
  • "However, I care if the constant reflection of properties will affect performance." You can mitigate this a bit by capitalizing on PropertyInfo , rather than what you load with reflection.
  • You can do something similar to reflection using expression trees, and you will see a significant performance boost from this. Here 's a blog post that will push you in the right direction on this issue. However, if you are not already familiar with working with expression trees, given the time constraints, this can lead to coding, testing, and debugging using a concept that you are not familiar with.
  • Are you sure this is even a performance bottleneck? It doesn’t shock me if network latency dominates here and you optimize prematurely.
+6
source

Generics are linked at compile time and will be as efficient as regular types. Reflection will be a huge cost.

0
source

If you're worried about performance, consider creating a DynamicMethod for each type of message. The code that the dynamic method will generate will be the same for all types of messages (just like it would with reflection), but once the dynamic method is created, you will not have a reflection of performance. The downside is that the code is harder to write and harder to debug, so this may not be the best option if you are under time pressure.

0
source

One approach that is often useful is to use Reflection with static generic classes. This is the approach used by things like EqualityComparer<T>.Default . Essentially, what happens for any particular type of T , the first reference to EqualityComparer<T>.Default will need to use Reflection to determine whether type T IComparable<T> and builds either an implementation of IEqualityComparer<T> that runs on unconstrained T and uses Object.Equals , and the other that binds T is IEqualityComparer<T> and uses IEqualityComparer<T>.Equals . Using reflection for this purpose is somewhat slow, but this needs to be done only once for any particular type of T After the implementation is built, it will be stored in the static field EqualityComparer<T> , so any future requests for default comparisons for this type can simply use the previously built implementation of IEqualityComparer<T> .

This approach combines the speed of generics with the flexibility to do things for which generics are not common.

0
source

Current code does this:

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

Creates a MemoryStream. Creates a BinaryReader reader in a stream. And then performs the action (reader).

Now suppose we have HelloMessage.cs, which has only two properties: a byte identifier and an int descriptor. The Decode method of the HelloMessageCodec.cs decoder class is as follows:

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

This is really beautifully done, but there are about 15 types of messages, and each type has its own xxxMessageCodec.cs with decoding and encoding implementations, each of which has properties passed manually to the Action delegate.

Now I need to do encryption, which means if I have to follow this pattern, I would have to build 15 different message ciphers.

I have already reworked the entire codec code to solution No. 2 (with reflection), and instead of 15 functions, I have only 2 functions + without basic levels, only two functions that process messages by their properties and call ReadByte, ReadInt32, ... depending on typeof property.

So, I have done this work, but I do not have enough time to test the performance, since I need to continue working on encryption. I have to choose one of two solutions to continue, and I have a sleep problem, will there be a smaller solution (reflection of one) to hit me in the face again :)

0
source

Source: https://habr.com/ru/post/913483/


All Articles