在我们当前的项目中,我们在类的静态构造函数中注册映射,这些类由多个线程调用。静态构造函数中的映射仅与该类相关。但仍然可以同时运行createmap的多个调用。此外,有时(主要是拷贝/过去的问题)相同的映射可以注册到不同类的静态构造函数中。
我试着用google搜索mapper.createmap是否是线程安全的。我只发现了以下几点:
在2012年的postIs Mapper.Map in AutoMapper thread-safe中,nemesv的答案中有一个注释,即createmap不是线程安全的,而且永远不会是线程安全的。
但我在github上发现了一个2014年的问题,在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中的值是相同的)。将map函数从两个线程更改有时会导致年龄值从负值变为正值(测试以不同年龄的高值结束)。但有时行为完全不同,年龄迭代停止值为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