在大比拼之前先讲一个小插曲,我这个人以前比较低调,做了很多好东西仅仅在公司内的朋友圈项目圈内分享,很少在博客园内进行分享,后来在dudu 老大的文章博客园现代化建设——AutoMapper有感便推荐一下OOMapper 组件,于是乎接连写了几篇入门性的介绍使用文章:

  • 开发人员必备工具:OOMapper
  • OO Mapper 实践(上篇)
  • OO Mapper 实践(下篇)

   在园友Repository 兄的NLiteMapper与EmitMapper性能简单比较中了解到NLiteMapper与EmitMapper的性能巨大差距,于是乎进行了两天的性能优化,同时总结了优化过程:一次性能优化最佳实践。在这里非常感谢Repository 兄的测试,也非常感谢他把OOMapper纠正为NLiteMapper,否则NLiteMapper的性能是非常低下的,同时感谢dudu,感谢博客园给大家一个平台,在这个平台使我学到了很多很多......

不说废话进入主题。

准备工作:

  •   软硬件环境:VS2008,.net3.5, xp 双核
  • 测试组件(都是最新Release版本):AutoMapper.dll(v2.0), EmitMappe.dll (V1.0),NLite.dll(V1.0)

性能测试工具:老赵的CodeTimer

测试接口代码:

[Contract]
public interface IObjectToObjectMapper
{
//初始化映射器
void Initialize();
//执行映射
void Map();
}

为了输出更友好的结果定义一下测试元数据代码:

//测试映射器元数据
public interface IMapperMetadata
{
//目录
string Category { get; }
//名称
string Name { get; }
string Descrption { get; }
}

//映射器元数据注解
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
[MetadataAttributeAttribute]
public class MapperAttribute : ComponentAttribute
{
public string Category { get; set; }
public string Name { get; set; }
public string Descrption { get; set; }
}

   利用NLite的Mini容器书写测试框架代码如下:测试次数10万次

class Program
{
[InjectMany]
private Lazy<IObjectToObjectMapper,IMapperMetadata>[] Mappers;

//初始化映射器,并做一次映射操作
void Init()
{
foreach (var item in Mappers)
{
item.Value.Initialize();
item.Value.Map();
}

}

//进行测试
void Run()
{
foreach (var item in Mappers)
CodeTimer.Time(item.Metadata.Category +"->" + item.Metadata.Name , 100000,() => item.Value.Map());
}

static void Main(string[] args)
{
ServiceRegistry.RegisteryFromAssemblyOf<Program>();

var host = new Program();
ServiceRegistry.Compose(host);

host.Init();
host.Run();

Console.Read();
}
}

这样完成了测试框架的搭建,现在就开始书写测试代码了。

  定义测试数据:

public class ModelObject
{
public DateTime BaseDate { get; set; }
public ModelSubObject Sub { get; set; }
public ModelSubObject Sub2 { get; set; }
public ModelSubObject SubWithExtraName { get; set; }
}

public class ModelSubObject
{
public string ProperName { get; set; }
public ModelSubSubObject SubSub { get; set; }
}

public class ModelSubSubObject
{
public string IAmACoolProperty { get; set; }
}

public class ModelDto
{
public DateTime BaseDate { get; set; }
public string SubProperName { get; set; }
public string Sub2ProperName { get; set; }
public string SubWithExtraNameProperName { get; set; }
public string SubSubSubIAmACoolProperty { get; set; }
}

   定义测试基类:

public abstract class MapperBase : IObjectToObjectMapper
{
protected ModelObject _source;
protected ModelDto _target;

protected virtual void OnInitialize() { }
public void Initialize()
{
OnInitialize();

_source = new ModelObject
{
BaseDate = new DateTime(2007, 4, 5),
Sub = new ModelSubObject
{
ProperName = "Some name",
SubSub = new ModelSubSubObject
{
IAmACoolProperty = "Cool daddy-o"
}
},
Sub2 = new ModelSubObject
{
ProperName = "Sub 2 name"
},
SubWithExtraName = new ModelSubObject
{
ProperName = "Some other name"
},
};
}

public abstract void Map();
}

手工映射代码:

[Mapper(Category = "Flattening.Class", Name = "Manual")]
public class ManualMapper : MapperBase
{
public override void Map()
{
var destination = new ModelDto
{
BaseDate = _source.BaseDate,
Sub2ProperName = _source.Sub2.ProperName,
SubProperName = _source.Sub.ProperName,
SubSubSubIAmACoolProperty = _source.Sub.SubSub.IAmACoolProperty,
SubWithExtraNameProperName = _source.SubWithExtraName.ProperName
};
}
}

AutoMapper 映射代码:

[Mapper(Category = "Flattening.Class", Name = "AutoMapper")]
public class AutoMapperWrapper : MapperBase
{
protected override void OnInitialize()
{
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.CreateMap<ModelObject, ModelDto>();
});
AutoMapper.Mapper.AssertConfigurationIsValid();
}

public override void Map()
{
_target =AutoMapper.Mapper.Map<ModelObject, ModelDto>(_source);
}
}

  EmitMapper映射代码:

[Mapper(Category = "Flattening.Class", Name = "EmitMapper")]
public class EmitMapperWrapper : MapperBase
{
ObjectsMapper<ModelObject, ModelDto> mapper;
protected override void OnInitialize()
{
mapper = ObjectMapperManager.DefaultInstance.GetMapper<ModelObject, ModelDto>(new FlatteringConfig());
}

protected override ModelDto MapImp()
{
return mapper.Map(Source);
}
}

EmitMapper映射器默认不支持Flatter 映射,如果支持需要写自定义配置:

class FlatteringConfig : DefaultMapConfig{protected Func<string, string, bool> nestedMembersMatcher;public FlatteringConfig(){nestedMembersMatcher = (m1, m2) => m1.StartsWith(m2);}public override IMappingOperation[] GetMappingOperations(Type from, Type to){var destinationMembers = GetDestinationMemebers(to);var sourceMembers = GetSourceMemebers(from);var result = new List<IMappingOperation>();foreach (var dest in destinationMembers){var matchedChain = GetMatchedChain(dest.Name, sourceMembers).ToArray();if (matchedChain == null || matchedChain.Length == 0){continue;}result.Add(new ReadWriteSimple{Source = new MemberDescriptor(matchedChain),Destination = new MemberDescriptor(new[] { dest })});}return result.ToArray();}public DefaultMapConfig MatchNestedMembers(Func<string, string, bool> nestedMembersMatcher){this.nestedMembersMatcher = nestedMembersMatcher;return this;}private List<MemberInfo> GetMatchedChain(string destName, List<MemberInfo> sourceMembers){var matches = sourceMembers.Where(s => MatchMembers(destName, s.Name) || nestedMembersMatcher(destName, s.Name));int len = 0;MemberInfo match = null;foreach (var m in matches){if (m.Name.Length > len){len = m.Name.Length;match = m;}}if (match == null){return null;}var result = new List<MemberInfo> { match };if (!MatchMembers(destName, match.Name)){result.AddRange(GetMatchedChain(destName.Substring(match.Name.Length), GetDestinationMemebers(match)));}return result;}private static List<MemberInfo> GetSourceMemebers(Type t){return GetMemebers(t).Where(m =>m.MemberType == MemberTypes.Field ||m.MemberType == MemberTypes.Property ||m.MemberType == MemberTypes.Method).ToList();}private static List<MemberInfo> GetDestinationMemebers(MemberInfo mi){Type t;if (mi.MemberType == MemberTypes.Field){t = mi.DeclaringType.GetField(mi.Name).FieldType;}else{t = mi.DeclaringType.GetProperty(mi.Name).PropertyType;}return GetDestinationMemebers(t);}private static List<MemberInfo> GetDestinationMemebers(Type t){return GetMemebers(t).Where(m => m.MemberType == MemberTypes.Field || m.MemberType == MemberTypes.Property).ToList();}private static List<MemberInfo> GetMemebers(Type t){BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public;return t.GetMembers(bindingFlags).ToList();}}

NLiteMapper映射代码:

[Mapper(Category = "Flattening.Class", Name = "NLiteMapper")]
public class NLiteMaperWrapper : MapperBase
{
private NLite.Mapping.IMapper<ModelObject, ModelDto> mapper;
protected override void OnInitialize()
{
base.OnInitialize();

mapper = NLite.Mapper.CreateMapper<ModelObject, ModelDto>();
}

public override void Map()
{
_target = mapper.Map(_source);
}
}

   Ok,完成代码用Release编译,然后再输出bin中找到exe文件,连续执行三次,下面是三次执行结果的截图:

------ Test started: Assembly: NLite.Test.dll ------Flattening.Class->AutoMapperTime Elapsed:  1,112msCPU Cycles:  6,718,750Gen 0:         173Gen 1:       1Gen 2:         0Flattening.Class->NLiteMapperTime Elapsed:  68msCPU Cycles: 781,250Gen 0:       4Gen 1:         1Gen 2:         0Flattening.Class->EmitMapperTime Elapsed:   23msCPU Cycles: 156,250Gen 0:       3Gen 1:         0Gen 2:         0Flattening.Class->ManualTime Elapsed:   8msCPU Cycles:  0Gen 0:         3Gen 1:         1Gen 2:         0

------ Test started: Assembly: NLite.Test.dll ------Flattening.Class->AutoMapperTime Elapsed:  1,701msCPU Cycles:  10,468,750Gen 0:        173Gen 1:       0Gen 2:         0Flattening.Class->NLiteMapperTime Elapsed:  69msCPU Cycles: 781,250Gen 0:       4Gen 1:         1Gen 2:         0Flattening.Class->EmitMapperTime Elapsed:   22msCPU Cycles: 0Gen 0:         3Gen 1:         0Gen 2:         0Flattening.Class->ManualTime Elapsed:   10msCPU Cycles: 312,500Gen 0:       3Gen 1:         1Gen 2:         01 passed, 0 failed, 0 skipped, took 2.98 seconds (NUnit 2.5.5).

------ Test started: Assembly: NLite.Test.dll ------Flattening.Class->AutoMapperTime Elapsed:  1,205msCPU Cycles:  10,156,250Gen 0:        177Gen 1:       0Gen 2:         0Flattening.Class->NLiteMapperTime Elapsed:  66msCPU Cycles: 781,250Gen 0:       4Gen 1:         0Gen 2:         0Flattening.Class->EmitMapperTime Elapsed:   18msCPU Cycles: 312,500Gen 0:       3Gen 1:         0Gen 2:         0Flattening.Class->ManualTime Elapsed:   9msCPU Cycles:  0Gen 0:         3Gen 1:         0Gen 2:         01 passed, 0 failed, 0 skipped, took 2.56 seconds (NUnit 2.5.5).

通过测试结果可以看出:

  •    手工映射速度最快
  • EmitMapper第二(大约比手工慢了2-6倍,)
  • NLiteMapper第三(大约比EmitMapper慢了3倍)
  • 最后是AutoMapper(大约比手工慢了200倍)

内存开销结果:

  1. 手工映射              Gen 0: 3
  2. EmitMapper         Gen 0:3
  3. NLiteMapper        Gen 0: 4
  4. AutoMapper        Gen 0:173

总结 :无论从性能和内存EmitMapper都接近于手工,NLiteMapper次之,AutoMapper最后。NLiteMapper,EmitMapper,AutoMapper都是通过Emit的方式进行Get和Set的,为什么性能差别如此之大,设想如果NLiteMapper不进行优化的话(NLiteMapper一直是通过Emit方式进行的),那么NLiteMapper肯定是高高垫背的(NLiteMapper比EmitMapper慢了15000倍)。。。。。。

  这次测试结果不代表整体结果,仅仅代表Class->Class(包括级联) 的映射性能,欢迎大家对这几种OO映射器进行性能比较。最后附上整个测试代码:测试代码。

  备注:EmitMapper的测试代码修改过,添加了FlatteringConfig class 这样测试就公平了。

附上的源代码是老代码,最新代码:http://nlite.codeplex.com/SourceControl/changeset/view/76359#1528885

EmitMapper,AutoMapper,NLiteMapper和手工映射性能大比拼相关推荐

  1. [转载]EmitMapper,AutoMapper,NLiteMapper和手工映射性能大比拼

    在大比拼之前先讲一个小插曲,我这个人以前比较低调,做了很多好东西仅仅在公司内的朋友圈项目圈内分享,很少在博客园内进行分享,后来在dudu 老大的文章博客园现代化建设--AutoMapper有感便推荐一 ...

  2. Class 创建性能大比拼(反射,泛型反射,泛型创建,缓存Emit,非缓存Emit)

    一说到反射,很多人都想到了性能,更有甚者直接说"慎用反射,遗患无穷","用反射,感觉怎么像是退步啊-",看到这种言论,直接把反射妖魔化了,如果这种言论长此以往, ...

  3. node和java性能_服务端I/O性能大比拼:Node、PHP、Java和Go(二)

    服务端I/O性能大比拼:Node.PHP.Java和Go(二) 服务端I/O性能大比拼:Node.PHP.Java和Go(二) ### 多线程的方式:Java 所以就在你买了你的第一个域名的时候,Ja ...

  4. 公共DNS性能大比拼

    ​ 今天中午,访问Gitee突然访问不进去,然后收到红薯通知:阿里云停止了 Gitee.com 的域名解析. ​ ​ 码云官方也随后给出解决办法 没有任何提示,没有任何提前通知,阿里云停止了 Gite ...

  5. Node和java和php,服务端I/O性能大比拼:Node、PHP、Java和Go(三)

    服务端I/O性能大比拼:Node.PHP.Java和Go(三) 服务端I/O性能大比拼:Node.PHP.Java和Go(三) 谎言,诅咒的谎言和基准 对这些各种模式的上下文切换进行准确的定时是很困难 ...

  6. 基于 abp vNext 和 .NET Core 开发博客项目 - 用AutoMapper搞定对象映射

    基于 abp vNext 和 .NET Core 开发博客项目 - 用AutoMapper搞定对象映射 转载于:https://github.com/Meowv/Blog 本篇紧接着来玩一下AutoM ...

  7. 曾辉机器人_6款国产SCARA机器人性能大比拼

    6款国产SCARA机器人性能大比拼 文章来源自:高工机器人网 2018-08-14 10:19:51 阅读:135793 摘要中国工业机器人市场经历了2017年的"爆发",2018 ...

  8. linux和mac运行效率,Windows vs Deepin Linux vs MacOS 终极一战之显卡性能大比拼

    1.前述 在前面的介绍里面欧巴云为大家分享了从Deepin Linux镜像下载.系统盘刻录.系统安装.显卡驱动安装等一系列教程,如果您还不了解怎么样安装Deepin Linux,可参考下方详细链接: ...

  9. Java分布式 RPC 框架性能大比拼,Dubbo真的最差吗?

    点击上方"搜云库技术团队",选择"设为星标" 回复"1024"或"面试题"获取学习资料 Dubbo 是阿里巴巴公司开源的 ...

最新文章

  1. 简单介绍.Net性能测试框架Crank的使用方法
  2. webdriver--单选、复选及下拉框的定位
  3. IIS8 使用FastCGI配置PHP环境支持 过程详解
  4. 01需求工程-软件建模与分析阅读笔记
  5. 【实战】数据可视化系统后端开发环境搭建
  6. 计算机的网络操作题,计算机网络操作题
  7. Abstract Factory(抽象工厂)--对象创建模式
  8. php怎么和数据库通信,php – 如何处理域和数据库层之间的通信?
  9. android 休眠唤醒驱动流程分析,Android4.0.4休眠唤醒机制分析(基于MSM8260)
  10. python 文本相似度现状_python文本相似度分析
  11. MySQL如何用一条SQL将一张表里的数据插入到另一张表
  12. 多线程编程:线程死锁的原因以及解决方法
  13. oracle数据库ora01012错误,Oracle自定义异常收集(二)
  14. 人教版五年级计算机教案,人教版信息技术五年级下册教案
  15. php 代付功能_常见的第三方支付平台代付接口(php源码)
  16. 【51单片机开发板】可调周期、占空比pwm工程
  17. 网易邮箱接收ibm的邮件_在IBM Integration Bus中发送和接收带有大型附件的SOAP消息
  18. 数学建模常用模型04 :灰色关联分析法
  19. 【LabVIEW串口编程】 02 串口发送
  20. HDLM命令dlnkmgr详解之三__view

热门文章

  1. mysql读写分离实现事务_Mysql读写分离后的事务ce
  2. 最长公共子序列-动态规划(C/C++)
  3. php魔术方法例子,PHP魔术方法示例
  4. html5液体效果,HTML5/CSS3/SVG实现的液体掉落(滑落)动画
  5. 变电站计算机监控系统相关技术,变电站计算机监控系统的研究
  6. java 1亿个数字中_求一亿个数字里面最小的10个数字
  7. 进度条上的小圆点怎么做_Android自定义带圆点的半圆形进度条
  8. Android 源码编译过程
  9. ubuntu 重装系统备份数据 ubuntu安装kde桌面
  10. 第2章 DOS循环:for命令详解