是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%的情况

是Automapper Mapper.CreateMap线程安全的

CreateMap是线程安全的。这并不意味着调用CreateMap的代码是。CreateMap应该只在每个AppDomain中调用一次,通常的方法是这样的:https://github.com/jbogard/ContosoUniversity/blob/master/src/ContosoUniversity/Infrastructure/Mapping/AutoMapperBootstrapper.cs

map不应该使用任何通过闭包传入的上下文数据。上面的代码一开始就是糟糕的映射,您应该重构它们,使用内置的方法来处理上下文数据https://stackoverflow.com/a/31754133/58508