Pull to refresh

Benchmark: AutoMapper vs BLToolkit vs EmitMapper

Reading time 3 min
Views 12K

О чем речь?


Речь в этой заметке пойдет о библиотеках для автоматического копирования полей одного объекта в поля другого (мэппинг объектов). О том, для чего это надо можно почитать, например, тут.

Предлагаю рассмотреть следующие библиотеки, с помощью которых можно решить вышеописанную задачу:

1) AutoMapper
2) BLToolkit
3) EmitMapper

Все эти библиотеки отличает тот факт, что они используют Emit для генерации кода во время выполнения, и потенциально могут работать с эффективностью приближенной к ручному кодированию. Так ли это, предлагаю проверить.

AutoMapper

Сайт: automapper.codeplex.com

На данный момент это самая распространенная библиотека. Библиотека содержит приличный набор медодов для расширения и кастомизации мэппинга, а также поддерживает работу со сложными вложенными объектами. Хотя для работы с последними придется дополнительно сделать «приседания», предварительно зарегистрировав каждую пару сопоставляемых типов.

BLToolkit

Сайт: bltoolkit.net

Это не чистый Objects to Objects мэппер (скорее это легковесная ORM), хотя и поддерживает мэппинг одних объектов в другие. Но из-за того, что это не чистый Objects to Objects мэппер у него отсутствуют многе возможности присущие полноценным мэпперам таким как AutoMapper или EmitMapper. Библиотека не поддерживает сложные объекты, да и сам мэппинг не может быть каким-либо способом кастомизирован.

EmitMapper

Сайт: emitmapper.codeplex.com

Свежая разработка. Весьма гибкая библиотека, которая позволяет мэппить почти все что угодно куда угодно. Например, можно самому написать для этой библиотеки конфигурацию мэппера, которая считает данные из DbDataReader и запишет их в некоторый объект. На данный момент, это единственная библиотека из рассматриваемых, доступная под Silverlight (по крайней мере в официальных релизах).

Сравнение производительности.


Для сравнение производительности были написаны следующие тесты.

Простой тест.

Сопоставляются два простых класса, все поля которых имеют примитивные типы и без какой-либо дополнительной кастомизации. Это единственный тест, который может быть выполнен на BLToolkit. Код теста можно найти здесь.

Результаты (время работы в миллисекундах):
Auto Mapper 36809
BLToolkit 34533
Emit Mapper 117
Handwritten Mapper 37

По цифрам видно, что разница очень впечатляющая, но для лучшего представления масштаба предлагаю посмотреть на диаграмму:

simple test

Вложенные классы.

Сопоставляются два класса, имеющие сложную структуру. Код теста можно посмотреть здесь.

Результаты (время работы в миллисекундах):
Auto Mapper 52238
Emit Mapper 102
Handwritten Mapper 97
BLToolkit не поддерживается

В данном тесте видно, что производительность Emit Mapper и ручного кода практически идентична.
Диаграмма:
nested classes

Кастомизация.

В данном тесте проверяется скорость работы сложного кастомизированного сопоставления. В частности активно используются Custom constructors, Null substitution и Custom converters. Код теста доступен здесь

Результаты (время работы в миллисекундах):
Auto Mapper 50142
Emit Mapper 197
BLToolkit не поддерживается

Диграмма:
customized mapping

Выводы


Продемонстрированная разница в производительности является весьма существенной и меняет сам подход к использования автоматических объектых мэпперов. Если в случае с AutoMapper мы должны постоянно держать в уме требования к данному участку кода (как часто он используется), то в случае с EmitMapper ничего этого не требуется. Мы просто выполняем мэппинг там, где нам нужно и знаем, что с производительностью будет все нормально.

P.S.: В комментариях резонно спросили о причинах такой разницы в производительности. Чтобы избежать недоразумений, вот они:
1) В EmitMapper есть возможность заранее сгенерировать мэппер и где-то его сохранить (например, во время старта программы в статическом поле). В AutoMapper и BLToolkit мы вынуждены использовать одну единственную глобальную точку входа типа: «Map.ObjectToObject(foo)». А это затраты на синхронизацию, поиск по словарю и т.д.
2) AutoMapper был изначально спроектирован и написан для Reflection и лишь потом переведен на Emit. Из-за этого там осталось очень много ненужного оверхеда.
3) EmitMapper практически нигде не использует boxing/unboxing в отличии от его конкурентов. Да и вообще, код, который он генерирует весьма эффективен.
Tags:
Hubs:
+12
Comments 20
Comments Comments 20

Articles