是Automapper Mapper.CreateMap线程安全的
本文关键字:安全 线程 CreateMap Automapper Mapper | 更新日期: 2023-09-27 18:06:01
在我们当前的项目中,我们正在多个线程调用的类的静态构造函数中注册映射。静态构造函数中的映射仅与该类相关。但是CreateMap的多个调用仍然可以同时运行。此外,偶尔(主要是复制/过去问题),相同的映射可以在不同类的静态构造函数中注册。
我试着谷歌地图是否。CreateMap是否线程安全。我只发现了以下内容:
In post Is Mapper。在nemesv的回答中注意到CreateMap不是线程安全的,而且永远不会是。
但是我发现GitHub静态动态地图和CreateMap api应该是线程安全的,从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中也有相同的值)。从两个线程更改映射函数有时会导致Age的交替值从负数增加到正数(测试以不同Age的高值结束)。但有时行为完全不同,Age迭代在值为1或-1时停止。如果这个映射函数从更多的线程中更改,似乎有一些内部机制冻结了映射函数的更改。但这并不是100%的情况
CreateMap是线程安全的。这并不意味着调用CreateMap的代码是。CreateMap应该只在每个AppDomain中调用一次,通常的方法是这样的:https://github.com/jbogard/ContosoUniversity/blob/master/src/ContosoUniversity/Infrastructure/Mapping/AutoMapperBootstrapper.cs
map不应该使用任何通过闭包传入的上下文数据。上面的代码一开始就是糟糕的映射,您应该重构它们,使用内置的方法来处理上下文数据https://stackoverflow.com/a/31754133/58508