.net 有没有办法提高Automapper的性能?

.net 有没有办法提高Automapper的性能?,.net,asp.net-mvc,performance,mapping,automapper,.net,Asp.net Mvc,Performance,Mapping,Automapper,我是汽车制造商的忠实粉丝。我现在在许多项目中使用它来映射不同领域之间的实体,比如从wcf服务模型到业务模型 在一个示例网站中进行了一些负载测试(使用VS Profiler)之后,我发现AutoMapper导致了高CPU消耗 我为这种行为做了一些单元: using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; using System.Diagnostics

我是汽车制造商的忠实粉丝。我现在在许多项目中使用它来映射不同领域之间的实体,比如从wcf服务模型到业务模型

在一个示例网站中进行了一些负载测试(使用VS Profiler)之后,我发现AutoMapper导致了高CPU消耗

我为这种行为做了一些单元:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace AutoMapper.Tests
{
    [TestClass]
    public class UnitTest
    {
        public class ClassSource
        {
            public string PropertyA { get; set; }
            public int PropertyB { get; set; }
            public NestedClassSource PropertyC { get; set; }
        }

        public class NestedClassSource
        {
            public string PropertyD { get; set; }
            public DateTime PropertyE { get; set; }
            public List<int> PropertyF { get; set; }
        }

        public class ClassDestination
        {
            public string PropertyA { get; set; }
            public int PropertyB { get; set; }
            public NestedClassDestination PropertyC { get; set; }
        }

        public class NestedClassDestination
        {
            public string PropertyD { get; set; }
            public DateTime PropertyE { get; set; }
            public List<int> PropertyF { get; set; }
        }

        [TestMethod]
        public void MappingPerfTests()
        {
            Mapper.Initialize(a =>
            {
                a.CreateMap<ClassSource, ClassDestination>();
                a.CreateMap<NestedClassSource, NestedClassDestination>();

            });
            Mapper.AssertConfigurationIsValid();

            IList<ClassSource> items = GenerateRandomSources(nbItems: 500);

            //automapper
            MicroBench(() =>
            {
                var res = Mapper.Map<IList<ClassSource>, IList<ClassDestination>>(items);
            }, nbIterations: 10);
            // will take nearly 30 ms per test
            // total : 300 ms


            //manual mapper
            MicroBench(() =>
            {
                var res = new List<ClassDestination>(items.Count);
                foreach (var source in items)
                {
                    res.Add(new ClassDestination()
                    {
                        PropertyA = source.PropertyA,
                        PropertyB = source.PropertyB,
                        PropertyC = new NestedClassDestination()
                        {
                            PropertyD = source.PropertyC.PropertyD,
                            PropertyE = source.PropertyC.PropertyE,
                            PropertyF = new List<int>(source.PropertyC.PropertyF)
                        }

                    });
                }
            }, nbIterations: 10);
            // will take nearly 0 ms per test
            // total : 1 ms

        }

        private IList<ClassSource> GenerateRandomSources(int nbItems = 1000)
        {
            IList<ClassSource> res = new List<ClassSource>(100);
            foreach (var i in Enumerable.Range(1, nbItems))
            {
                ClassSource item = new ClassSource()
                {
                    PropertyA = "PropertyA",
                    PropertyB = i,
                    PropertyC = new NestedClassSource() { PropertyD = "PropertyD", PropertyE = DateTime.Now, PropertyF = Enumerable.Range(1, 10).ToList() }
                };
                res.Add(item);
            }
            return res;
        }

        private void MicroBench(Action action, int nbIterations = 1000)
        {
            long totalElapsed = 0L;

            foreach (var i in Enumerable.Range(1, nbIterations))
            {
                Stopwatch watcher = Stopwatch.StartNew();

                action();

                watcher.Stop();
                Console.WriteLine("test : {0} ms", watcher.ElapsedMilliseconds);
                totalElapsed += watcher.ElapsedMilliseconds;
            }

            Console.WriteLine("total : {0} ms", totalElapsed);
            Console.WriteLine("avg : {0} ms", totalElapsed / nbIterations);

        }
    }
}
使用Microsoft.VisualStudio.TestTools.UnitTesting;
使用制度;
使用System.Collections.Generic;
使用系统诊断;
使用System.Linq;
名称空间AutoMapper.Tests
{
[测试类]
公共类单元测试
{
公共类类源
{
公共字符串属性{get;set;}
公共int属性b{get;set;}
公共NestedClassSource属性{get;set;}
}
公共类嵌套类源
{
公共字符串PropertyD{get;set;}
公共日期时间属性{get;set;}
公共列表属性f{get;set;}
}
公共类目的地
{
公共字符串属性{get;set;}
公共int属性b{get;set;}
公共NestedClassDestination PropertyC{get;set;}
}
公共类NestedClassDestination
{
公共字符串PropertyD{get;set;}
公共日期时间属性{get;set;}
公共列表属性f{get;set;}
}
[测试方法]
公共void MappingPerfTests()
{
Mapper.Initialize(a=>
{
a、 CreateMap();
a、 CreateMap();
});
assertConfigurationsValid();
IList items=GeneratorDomainSources(nbItems:500);
//汽车制造商
微边界(()=>
{
var res=Mapper.Map(项目);
},次为10次;
//每次测试大约需要30毫秒
//总数:300毫秒
//手动制图器
微边界(()=>
{
var res=新列表(items.Count);
foreach(项目中的var源)
{
res.Add(新类目的地()
{
PropertyA=source.PropertyA,
PropertyB=source.PropertyB,
PropertyC=新的NestedClassDestination()
{
PropertyD=source.PropertyC.PropertyD,
PropertyE=source.PropertyC.PropertyE,
PropertyF=新列表(source.PropertyC.PropertyF)
}
});
}
},次为10次;
//每次测试大约需要0毫秒
//总数:1毫秒
}
专用IList生成器域源(int nbItems=1000)
{
IList res=新名单(100);
foreach(可枚举范围内的var i(1,nbItems))
{
ClassSource项=新的ClassSource()
{
PropertyA=“PropertyA”,
属性b=i,
PropertyC=newnestedClassSource(){PropertyD=“PropertyD”,PropertyE=DateTime。现在,PropertyF=Enumerable.Range(1,10).ToList()}
};
决议增补(项目);
}
返回res;
}
私有void微边界(Action-Action,int-nbIterations=1000)
{
长时间总消耗=0升;
foreach(可枚举范围内的var i(1,n次迭代))
{
Stopwatch watcher=Stopwatch.StartNew();
动作();
watcher.Stop();
WriteLine(“test:{0}ms”,watcher.elapsedmillesons);
总已用时间+=watcher.elapsedmillyses;
}
WriteLine(“总计:{0}ms”,总计已用时间);
WriteLine(“平均:{0}毫秒”,总已用时间/NB迭代次数);
}
}
}
最后,AutoMapper看起来相当慢:平均每次测试30毫秒,而手动映射需要不到一毫秒的时间。我是“唯一”映射500个“简单”对象!也许对于MVC ViewModel来说,这种情况很少发生,但其他映射这种情况的人可能会很频繁

30毫秒似乎很快,但真正的问题是,这30毫秒(免费)是web服务器上的CPU时间服务器将如何处理重负载(100个并发用户)?事实上不太好,这就是我们的负载测试发出警告的原因

我找到了一种使用Mapper.CreateMapExpression生成linq表达式的方法,但不幸的是,该表达式不包含嵌套类型或选项

那么,有没有办法提高AutoMapper的性能? 是否有最佳实践


谢谢,

阅读本文,了解AutoMapper及其替代产品以及性能指标。我认为这会给你更全面的观点,你不会太在意性能

我的观点与此相似——你的问题没有正确的答案(你在帖子中没有真正提出问题:)。您需要在CPU时间和人工时间(维护)之间保持平衡,并且无法对两者进行比较。但是这个IMHO应该是决定性的因素,但是很明显,它取决于你采取什么样的方法

编辑

试着看看这里,看看你是否找到了一些与你的处境相关的线索:

还有另一个链接(虽然从2009年开始),但可能仍然相关。。。


谢谢,希望这能有所帮助。

当然可以。但是Automapper已经出现在我们的项目中,我们的开发团队已经了解到了这一点。我只是在寻找提高性能的技巧,因为负载测试结果对automapper不是很好。