Emit mapper vs valueinjecter or automapper perform

2019-01-17 11:12发布

问题:

I have spent some time comparing this three mappers and it is interesting why so big performance diffrenece between emitmapper and any of valueinjecter or automapper(last two comparable by performance). From benchmark test in emitmapper solution (1000000 iterations):

    Auto Mapper (simple):        38483 milliseconds
    Emit Mapper (simple):        118 milliseconds
    Handwritten Mapper (simple): 37 milliseconds

    Auto Mapper (Nested):        53800 milliseconds
    Emit Mapper (Nested):        130 milliseconds
    Handwritten Mapper (Nested): 128 milliseconds

    Auto Mapper (Custom):        49587 milliseconds
    Emit Mapper (Custom):        231 milliseconds

Also some benchmarks from valueinjecter runned with added emitmapper(for 10000 iterations):

    Convention: 00:00:00.5016074
    Automapper: 00:00:00.1992945 
    Smart convention: 00:00:00.2132185
    Emit mapper(each time new mapper): 00:00:00.1168676
    Emit mapper(one mapper): 00:00:00.0012337

There in first emit mapper test - it was created each time, in second - one mapper for all conversions.

Taking this into account, have result as valueinjecter(also as automapper) slower than in 100 times than emit mapper. What is a reason of so huge performance difference? As for me object to object mapper cannot took so much time comparing to handwritten mapper as it be a bottleneck of project(if we need to map collection of objects for example).

At this moment I'm thinking about using emit mapper, but only one reason why I'm not ready to decide: emit mapper not supported at all by first developers, but I'm not sure that this is very important(very low possibility to requirement of some additional functionality).

回答1:

The reason is explained int the EmitMapper documentation:

It effectively uses the Emit library to generate mappers at run-time direct in IL as though these mappers are written by hand. Most other mappers use the Reflection library for mapping (or source code generation). Also EmitMapper minimizes boxing-unboxing operations and additional calls during mapping. For example it performs type conversion for value-types without boxing-unboxing and converts nested members without recursion (one-pass algorithm) when it is possible.

Reflection is extremely slow compared to handwritten code. EmitMapper instead, compared to handwritten mapping, has only the startup overhead when it emits.