나는 AutoMapper를 좋아한다. 나는 wcf 서비스 모델에서 비즈니스 모델에 이르기까지 서로 다른 도메인 사이의 엔티티 매핑을 위해 많은 프로젝트에서 이것을 사용하고있다.Automapper 성능을 향상시키는 방법은 무엇입니까?
샘플 웹 사이트에서 일부 부하 테스트 (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);
}
}
}
는 AutoMapper은 아주 느린 : 시험 당 평균 30 밀리 수동 매핑 미만 MS 걸리는 반면. 나는 "단지"500 개의 "단순한"객체를 매핑합니다! 어쩌면 MVC ViewModel의 경우 이것은 거의 발생하지 않지만 매핑하는 다른 MVC는 자주 발생할 수 있습니다.
30ms는 빠르지 만 실제 문제는이 30ms (아무 것도 없음)가 입니다. 웹 서버의 CPU 시간이 서버가 과다한 부하 (동시 사용자 100 명)를 어떻게 처리합니까? 사실, 우리 짐 테스트가 경고를 던지는 이유입니다.
Mapper.CreateMapExpression으로 linq 표현식을 생성하는 방법을 찾았지만 불행히도 표현식에 중첩 유형이나 옵션이 포함되어 있지 않습니다.
따라서 AutoMapper 성능을 향상시킬 수있는 방법이 있습니까? 모범 사례가 있습니까? 이 문서에
물론 가능합니다. 그러나 Automapper는 이미 프로젝트에 포함되어 있으며 개발 팀에서는이를 배웠습니다. 부하 테스트 결과가 자동 작업자에게는 좋지 않기 때문에 성능 향상을위한 도움말을 검색하고 있습니다. – Cybermaxs