在我们当前的项目中,我们在类的静态构造函数中注册映射,这些构造函数由多个线程调用。静态构造函数中的映射仅与该类相关。但是仍然可以同时运行多个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%的情况下发生
答案 0 :(得分:4)
CreateMap是线程安全的。这并不意味着你的代码调用CreateMap。每个AppDomain只应调用一次CreateMap,通常的方式如下:https://github.com/jbogard/ContosoUniversity/blob/master/src/ContosoUniversity/Infrastructure/Mapping/AutoMapperBootstrapper.cs
地图不应使用通过闭包传递的任何上下文数据。您上面的代码是开头的坏地图,您应该重构它们以使用内置的上下文数据方法https://stackoverflow.com/a/31754133/58508