Struct 생성 성능 비교 (반사, 일반 반사, 일반 생성, 캐시 Emit)

12720 단어 struct
전편 소개Class 생성 성능 비교 (반사, 일반 반사, 일반 생성, 캐시 Emit, 비 캐시 Emit), 여기서 요약(10만 회 집행)
  • 가장 빠른 5ms
  • Class 객체 직접 작성
  • 캐시 Emit 6ms(Emit 시간 제외)
  • 범형반사 147ms
  • 범용 생성 159ms(사실은 컴파일러의 문법 설탕이고 내부는 범용 반사로 호출됨)
  • 340ms
  • 반사
  • 캐시 미지원 Emit 12786ms
  • 위의 비교를 통해 Class 작성 지침을 잘 알 수 있습니다.
    직접 생성 -> 캐시 Emit-> 일반 반사 -> 일반 생성 -> 반사 (직접 호출보다 약 68배 느린 반사) 로 캐시 Emit이 아닌 것을 피합니다.
    Struct의 성능 비교Struct와 Class는 하나의 값 형식이고 하나의 인용 형식이며 하나의 창고에 분배되고 하나의 무더기에 분배되기 때문에 Class에서 창설하는 원칙이 모두 Struct에서 창설하는 원칙과 일치하는 것은 아니다.우리는 여전히 코드로 이야기한다.
    테스트된 Struct:
    
      
      
    struct TestEntity { }

       1. 수동으로 만들기
    
      
      
    [TestInfo(Category = " Struct.Constructor " , Name = " Direct " )]
    class DirectInvokeMode : IRunable
    {
    public void Run()
    {
    new TestEntity();
    }
    }

      2. 반사 생성
    
      
      
    [TestInfo(Category = " Struct.Constructor " , Name = " Reflect " )]
    class ReflectInvokeMode : IRunable
    {
    public void Run()
    {
    Activator.CreateInstance(
    typeof (TestEntity));
    }
    }

      3. 일반 반사 생성
    
      
      
    [TestInfo(Category = " Struct.Constructor " , Name = " GenericReflect " )]
    class GenericReflectInvokeMode : IRunable
    {
    public void Run()
    {
    Activator.CreateInstance
    < TestEntity > ();
    }
    }

      4. 일반 직접 생성
    
      
      
    [TestInfo(Category = " Struct.Constructor " , Name = " Generic Create " )]
    class GenericCreateInvokeMode : IRunable
    {
    public void Run()
    {
    Create
    < TestEntity > ();
    }

    static T Create < T > () where T : new ()
    {
    return new T();
    }
    }

      5. 캐시 Emit 생성: 구조체에 기본 구조 함수가 없기 때문에 IL로 emit를 할 수 없습니다. 여기서 ExpressionTree로 Emit을 진행합니다.
     /// <summary>
            ///           
            /// </summary>
            /// <param name="type"></param>
            /// <returns></returns>
            public static DefaultConstructorHandler GetDefaultCreator(this Type type)
            {
                if(type == Types.String)
                {
                    DefaultConstructorHandler s = ()=>null;
                    return s;
                }
    
                var ctorExpression = Expression.Lambda<DefaultConstructorHandler>(Expression.Convert(Expression.New(type), typeof(object)));
                var ctor = ctorExpression.Compile();
    
                DefaultConstructorHandler handler = () =>
                {
                    try
                    {
                        return ctor();
                    }
                    catch (TargetInvocationException ex)
                    {
                        throw ex.InnerException.Handle();
                    }
                    catch (Exception ex)
                    {
                        throw ex.Handle();
                    }
                };
    
                return handler;
            }
    

    위의 Emit 코드를 기반으로 작성된 Struct의 코드는 다음과 같습니다.
    [TestInfo(Category = "Struct.Constructor", Name = "Emit")]
            class EmitInvokeMode : IRunable
            {
                //           
                static readonly DefaultConstructorHandler Ctor = typeof(TestEntity).GetDefaultCreator();
    
                public void Run()
                {
                    Ctor();
                }
            }
    

    테스트 함수:
    
      
      
    for ( int i = 0 ; i < 3 ; i ++ )
    {
    foreach (var item in Mappers)
    CodeTimer.Time(item.Metadata.Category
    + " -> " + item.Metadata.Name, 100000 , () => item.Value.Run());
    }

    출력 결과는 다음과 같습니다.
    ------ Test started: Assembly: NLite.Test.dll ------
    
    Struct.Constructor->Direct
    	Time Elapsed:	4ms
    	CPU Cycles:	156,250
    	Gen 0: 		0
    	Gen 1: 		0
    	Gen 2: 		0
    
    Struct.Constructor->Reflect
    	Time Elapsed:	330ms
    	CPU Cycles:	2,968,750
    	Gen 0: 		1
    	Gen 1: 		0
    	Gen 2: 		0
    
    Struct.Constructor->GenericReflect
    	Time Elapsed:	26ms
    	CPU Cycles:	156,250
    	Gen 0: 		1
    	Gen 1: 		0
    	Gen 2: 		0
    
    Struct.Constructor->Generic Create
    	Time Elapsed:	3ms
    	CPU Cycles:	156,250
    	Gen 0: 		0
    	Gen 1: 		0
    	Gen 2: 		0
    
    Struct.Constructor->Emit
    	Time Elapsed:	7ms
    	CPU Cycles:	0
    	Gen 0: 		1
    	Gen 1: 		0
    	Gen 2: 		0
    
    Struct.Constructor->Direct
    	Time Elapsed:	1ms
    	CPU Cycles:	0
    	Gen 0: 		0
    	Gen 1: 		0
    	Gen 2: 		0
    
    Struct.Constructor->Reflect
    	Time Elapsed:	329ms
    	CPU Cycles:	3,281,250
    	Gen 0: 		0
    	Gen 1: 		0
    	Gen 2: 		0
    
    Struct.Constructor->GenericReflect
    	Time Elapsed:	22ms
    	CPU Cycles:	312,500
    	Gen 0: 		0
    	Gen 1: 		0
    	Gen 2: 		0
    
    Struct.Constructor->Generic Create
    	Time Elapsed:	4ms
    	CPU Cycles:	156,250
    	Gen 0: 		0
    	Gen 1: 		0
    	Gen 2: 		0
    
    Struct.Constructor->Emit
    	Time Elapsed:	3ms
    	CPU Cycles:	156,250
    	Gen 0: 		0
    	Gen 1: 		0
    	Gen 2: 		0
    
    Struct.Constructor->Direct
    	Time Elapsed:	1ms
    	CPU Cycles:	0
    	Gen 0: 		0
    	Gen 1: 		0
    	Gen 2: 		0
    
    Struct.Constructor->Reflect
    	Time Elapsed:	339ms
    	CPU Cycles:	3,437,500
    	Gen 0: 		0
    	Gen 1: 		0
    	Gen 2: 		0
    
    Struct.Constructor->GenericReflect
    	Time Elapsed:	22ms
    	CPU Cycles:	312,500
    	Gen 0: 		0
    	Gen 1: 		0
    	Gen 2: 		0
    
    Struct.Constructor->Generic Create
    	Time Elapsed:	2ms
    	CPU Cycles:	0
    	Gen 0: 		0
    	Gen 1: 		0
    	Gen 2: 		0
    
    Struct.Constructor->Emit
    	Time Elapsed:	3ms
    	CPU Cycles:	0
    	Gen 0: 		0
    	Gen 1: 		0
    	Gen 2: 		0
    
    
    1 passed, 0 failed, 0 skipped, took 2.53 seconds (NUnit 2.5.5).
    

    테스트 결과에서 알 수 있듯이 범용 창설은 Emit을 초과하고 범용 반사를 초과한다. 이것은Class의 창설 테스트에서 Emit은 범용 반사를 초과하고 범용 반사는 범용 창설을 초과한다.

    좋은 웹페이지 즐겨찾기