C# Automapper.CreateMap线程安全吗?
在我们当前的项目中,我们在由多个线程调用的类的静态构造函数中注册映射。静态构造函数中的映射仅与该类相关。但仍然可以同时运行多个CreateMap调用。此外,偶尔(主要是拷贝/过去问题)可以在不同类的静态构造函数中注册相同的映射 我试着用谷歌搜索Mapper.CreateMap是否是线程安全的。我发现只有以下几点: 在2012年的帖子中,nemesv的回答中提到CreateMap不是线程安全的,而且永远不会 但我在GitHub上发现了一个2014年的问题,该问题在3.2版本中标记为已关闭。这表明CreateMap现在应该是线程安全的 您能确认CreateMap是线程安全的吗?我做了一些测试,看起来应该是这样的,但如果有更深入的知识的人能够确认这一信息,那就好了 编辑 经过一些额外的测试,CreateMap行为似乎非常有趣: 我使用以下代码进行测试C# Automapper.CreateMap线程安全吗?,c#,multithreading,automapper,C#,Multithreading,Automapper,在我们当前的项目中,我们在由多个线程调用的类的静态构造函数中注册映射。静态构造函数中的映射仅与该类相关。但仍然可以同时运行多个CreateMap调用。此外,偶尔(主要是拷贝/过去问题)可以在不同类的静态构造函数中注册相同的映射 我试着用谷歌搜索Mapper.CreateMap是否是线程安全的。我发现只有以下几点: 在2012年的帖子中,nemesv的回答中提到CreateMap不是线程安全的,而且永远不会 但我在GitHub上发现了一个2014年的问题,该问题在3.2版本中标记为已关闭。这表明C
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; }
}
公共无效测试()
{
var items=新列表();
对于(int i=0;i<100000;i++)
{
添加(新实体A{FirstName=“A”+i});
}
ManualResetEvent stopChangingMappingFunction=新的ManualResetEvent(错误);
线程t1=新线程(()=>
{
int i=1;
while(true)
{
if(stopChangingMappingFunction.WaitOne(TimeSpan.Zero))
返回;
var i1=i++;
Mapper.CreateMap().formMember(x=>x.Age,y=>y.ResolveUsing(newfunc(a=>i1));
}
});
线程t2=新线程(()=>
{
int i=-1;
while(true)
{
if(stopChangingMappingFunction.WaitOne(TimeSpan.Zero))
返回;
var i1=i--;
Mapper.CreateMap().formMember(x=>x.Age,y=>y.ResolveUsing(newfunc(a=>i1));
}
});
列表distinctAges1=null;
列表distinctAges2=null;
线程t3=新线程(()=>
{
睡眠(1000);
var res=Mapper.Map(项目);
distinctAges1=res.Select(x=>x.Age).Distinct().ToList();
睡眠(1000);
var res2=Mapper.Map(项目);
distinctAges2=res.Select(x=>x.Age).Distinct().ToList();
stopChangingMappingFunction.Set();
});
t1.Start();
t2.Start();
t3.Start();
t1.Join();
t2.连接();
t3.Join();
WriteLine(“第一个映射:”+string.Join(“,”,distinctAges1.ToArray());
WriteLine(“第二个映射:”+string.Join(“,”,distinctAges2.ToArray());
Console.ReadKey();
}
公共类实体
{
公共字符串名{get;set;}
}
公共类实体B
{
公共字符串名{get;set;}
公共整数{get;set;}
}
在我所有的测试中,当调用第一个Map方法时,这意味着CreateMap被冻结,无法对映射函数进行更多的更改(distinctAges1始终是一个唯一的值,distinctAges2中有相同的值)。从两个线程更改map函数有时会导致年龄的交替值从负数增加到正数(测试以不同年龄的高值结束)。但有时行为完全不同,年龄迭代在值为1或-1时停止。如果映射函数由多个线程更改而来,则似乎有一些内部机制冻结了对映射函数的更改。但这在100%的情况下都没有发生CreateMap是线程安全的。这并不意味着调用CreateMap的代码是正确的。每个AppDomain只能调用一次CreateMap,通常的方法如下:
映射不应使用通过闭包传入的任何上下文数据。您上面的代码一开始就是糟糕的映射,您应该对它们进行重构,以使用上下文数据的内置方式@usr什么使您认为它不是?至少在3.2之前它不是线程安全的。现在应该是了,但是一些“证据”就可以了,比如来自文档的证据:-)问题很清楚,我把它写给了一些人删除了评论:)请阅读这里:给Lior Dadon-请仔细阅读我的问题。我在我的问题中提到了您的链接,另外我添加了另一个链接,该链接建议CreateMap应该是3.2版的线程安全的。在这个示例中,我试图演示如何更改映射函数。在实际项目中,这不应该是一个问题。事实上,我们在多个位置(在需要映射的类的静态构造函数中)有CreateMap。原因是更好的维护(CrtMp靠近使用映射fnct的位置)。在多线程环境中,只有这种方法存在问题:一个线程调用Map,另一个线程调用CreateMap。在极少数情况下(ctrl+c、ctrl+v问题),CreateMap会尝试在多个位置注册相同的映射函数。因此,我对可能的后果感兴趣。@Jimmy链接的AutoMapperBootstrapper类已经被重构。删除该类的提交是: