在我们当前的项目中,我们在类的静态构造函数中注册映射,这些构造函数由多个线程调用.静态构造函数中的映射仅与该类相关.但是仍然可以同时运行多个CreateMap调用.此外,偶尔(主要是复制/过去的问题)相同的映射可以在不同类的静态构造函数中注册.
我试图谷歌是否Mapper.CreateMap是线程安全的.我发现只有以下内容:
在2012年的Is Mapper.Map in AutoMapper thread-safe之后,在nemesv的回答中注意到CreateMap不是线程安全的,它永远不会.
但是我在2014年的GitHub Static DynamicMap and CreateMap APIs should be thread-safe上发现了一个问题,在3.2版本中被标记为关闭.这表明CreateMap现在应该是线程安全的.
你能确认CreateMap是线程安全的吗?我进行了一些测试,它看起来应该是,但如果有更深入了解的人可以确认这些信息就可以了.
编辑
经过一些额外的测试后,似乎CreateMap行为非常有趣:
我使用以下代码进行测试
public void Test()
{
var items = new List<EntityA>();
for (int i = 0; i < 100000; i++)
{
items.Add(new EntityA { FirstName = "A" + i });
}
ManualResetEvent stopChangingMappingFunction = new ManualResetEvent(false);
Thread t1 = new Thread(() =>
{
int i = 1;
while (true)
{
if (stopChangingMappingFunction.WaitOne(TimeSpan.Zero))
return;
var i1 = i++;
Mapper.CreateMap<EntityA, EntityB>().ForMember(x => x.Age, y => y.ResolveUsing(new Func<EntityA, object>(a => i1)));
}
});
Thread t2 = new Thread(() =>
{
int i = -1;
while (true)
{
if (stopChangingMappingFunction.WaitOne(TimeSpan.Zero))
return;
var i1 = i--;
Mapper.CreateMap<EntityA, EntityB>().ForMember(x => x.Age, y => y.ResolveUsing(new Func<EntityA, object>(a => i1)));
}
});
List<int> distinctAges1 = null;
List<int> distinctAges2 = null;
Thread t3 = new Thread(() =>
{
Thread.Sleep(1000);
var res = Mapper.Map<IList<EntityA>, IList<EntityB>>(items);
distinctAges1 = res.Select(x => x.Age).Distinct().ToList();
Thread.Sleep(1000);
var res2 = Mapper.Map<IList<EntityA>, IList<EntityB>>(items);
distinctAges2 = res.Select(x => x.Age).Distinct().ToList();
stopChangingMappingFunction.Set();
});
t1.Start();
t2.Start();
t3.Start();
t1.Join();
t2.Join();
t3.Join();
Console.WriteLine("First Mapping: " + string.Join(", ", distinctAges1.ToArray()));
Console.WriteLine("Second Mapping: " + string.Join(", ", distinctAges2.ToArray()));
Console.ReadKey();
}
public class EntityA
{
public string FirstName { get; set; }
}
public class EntityB
{
public string FirstName { get; set; }
public int Age { get; set; }
}
在我调用第一个Map方法的所有测试中,这意味着CreateMap被冻结,并且不能再对映射函数进行更改(distinctAges1始终是一个唯一值,而且相同的值在distinctAges2中).从两个线程更改地图功能有时会导致Age从负数到正数的交替值增加(测试以不同年龄的高值结束).但有时行为完全不同,年龄迭代停止在1或-1的值.如果这个映射函数从更多线程更改,似乎有一些内部机制冻结映射函数的更改.但这种情况并非在100%的情况下发生
最佳答案
CreateMap是线程安全的.这并不意味着你的代码调用CreateMap.每个AppDomain只应调用一次CreateMap,通常的方法是这样的:https://github.com/jbogard/ContosoUniversity/blob/master/src/ContosoUniversity/Infrastructure/Mapping/AutoMapperBootstrapper.cs
地图不应使用通过闭包传递的任何上下文数据.你上面的代码是开始的坏地图,你应该重构它们以使用内置的上下文数据方法https://stackoverflow.com/a/31754133/58508
相关文章