2009-04-21 7 views
59

최근 비즈니스 계층에서 DataAccessProvider를 구별 할 수있는 인터페이스 계층을 만들었습니다. 이 방법을 사용하면 Web/App.Config의 값을 변경하여 언제든지 DataAccessProvider를 선택할 수 있습니다. (자세한 내용은 필요한 경우 제공 될 수 있음).리플렉션 속도가 느림

어쨌든 이것을 수행하기 위해 리플렉션을 사용하여 우리가 작업 할 수있는 DataProvider 클래스를 완성합니다.

/// <summary> 
/// The constructor will create a new provider with the use of reflection. 
/// If the assembly could not be loaded an AssemblyNotFoundException will be thrown. 
/// </summary> 
public DataAccessProviderFactory() 
{ 
    string providerName = ConfigurationManager.AppSettings["DataProvider"]; 
    string providerFactoryName = ConfigurationManager.AppSettings["DataProviderFactory"]; 
    try 
    { 
     activeProvider = Assembly.Load(providerName); 
     activeDataProviderFactory = (IDataProviderFactory)activeProvider.CreateInstance(providerFactoryName); 
    } 
    catch 
    { 
     throw new AssemblyNotFoundException(); 
    } 
} 

하지만 이제는 천천히 반사하는 것이 궁금합니다.

+4

벤치마킹 테스트 하네스를 만드는 것이 쉽지 않을까요? – marijne

+2

팩토리가 싱글 톤인 경우 Assembly.Load는 한 번만 호출됩니다. – CVertex

+0

http://stackoverflow.com/questions/25458/how-costly-is-net-reflection?rq=1 – nawfal

답변

72

대부분의 경우 : 충분히 빠릅니다. 예를 들어 DAL 래퍼 개체를 만드는 데이 개체를 사용하는 경우 리플렉션을 통해 개체를 만드는 데 걸리는 시간은 네트워크에 연결해야하는 시간과 비교하여 소문자입니다. 그래서 이것을 최적화하는 것은 시간 낭비 일 것입니다. 당신이 꽉 루프에서 반사를 사용하는 경우

은 그것을 개선하는 트릭이있다 :

  • 제네릭 입력 된 대리인에게
  • Delegate.CreateDelegate ((래퍼 where T : new()MakeGenericType를 사용)이 작동하지 않습니다 생성자)에 대한
  • Reflection.Emit은 - 하드 코어
  • Expression (같은 Delegate.CreateDelegate하지만, 더 유연하고
  • ) 생성자 작동

하지만 용도로는 CreateInstance입니다. 그것에 매달리고, 물건을 간단하게해라.


편집 : 가장 중요한 것은, "그것을 측정은"유지하면서 상대적으로 성능에 대한 포인트가 남아있는 동안, 나는 위의 일부를 명확히해야한다. 때로는 ... 과 관련이 있습니다. 먼저 측정하십시오. 그러나 이 너무 느리다면이 너무 느립니다. FastMember과 같은 것을 보길 원할 것입니다. Reflection.Emit 코드를 조용히 배경으로 사용하면 좋은 API를 쉽게 얻을 수 있습니다.

var accessor = TypeAccessor.Create(type); 
List<object> results = new List<object>(); 
foreach(var row in rows) { 
    object obj = accessor.CreateNew(); 
    foreach(var col in cols) { 
     accessor[obj, col.Name] = col.Value; 
    } 
    results.Add(obj); 
} 

매우 간단하지만 매우 빠릅니다.

int id = 12345; 
var orders = connection.Query<Order>(
    "select top 10 * from Orders where CustomerId = @id order by Id desc", 
    new { id }).ToList(); 
: 특정 예에서 나는 다시 당신에게 가장 빠른하지만 사용하기 쉬운 API를 제공하는 백그라운드에서 모든 Reflection.Emit 코드를 수행 dapper 같은 DAL이 많은 일을하는 경우 랩퍼 고려 뭔가에 대해 언급
+2

누군가가 반사 방출이 필드에 액세스하는 방법을보고 싶다면 (너무 복잡하지는 않음) 참조 : http : //sharpanalytics.blogspot.de/2012/08/dynamic-methods-for-accessing-fields.html – SACO

+0

@Marc : \t 메소드를 가져 오기 위해 리플렉션을 사용했습니다. 현재 메소드의 클래스 이름을 try에 오류로 기록합니다. -잡기. 기본적으로 오류를 로깅하는 동안 함수 이름을 하드 코딩하지 않도록합니다. 걱정해야합니까? –

+1

@Sangram 아니, 아니 –

9
+5

충격을받지 마십시오. 측정 된 가장 긴 시간은 백만 회 반복 당 22 초입니다. 최악의 경우 통화 당 22 * ​​마이크로 * 초. 엄청난 수의 객체를 만드는 경우가 아니면 큰 문제가 아닙니다. 물론 많은 수의 객체를 생성하는 경우 큰 문제가 될 수 있지만 Marc이 지적 하듯이 데이터베이스 연결 및 쿼리 시간에 의해 여전히 침체 될 것입니다. 퍼포먼스에 중대한 사항이 없다면 "느린"x 번 기사로 놀라지 마십시오. – itowlson

+0

비록 느리지 만 대부분의 응용 프로그램에서는 성능 저하가 Reflection 사용의 이점보다 중요하지 않다고 동의합니다. –

3

다른 답변에서 주어진 링크를 따르지 않고 "pathalogically bad"코드를 쓰지 않는 것 이외에 나에게 가장 좋은 대답은 직접 테스트하는 것입니다.

리플렉션 코드가 좁은 루프에있을 지 여부와 같은 네크 병의 위치, 리플렉션 코드의 사용자 수, 비즈니스 케이스, 사이트에 액세스 할 사용자 수, 요구 사항은 다음과 같습니다.

그러나 여기에 표시된 코드 스 니펫을 보면 내 생각에 반사의 오버 헤드가 엄청난 문제가되지는 않을 것입니다.

VS.NET 웹 테스트 및 성능 테스트 기능을 사용하면이 코드의 성능을 매우 간단하게 측정 할 수 있습니다.

리플렉션을 사용하지 않으면 코드는 어떻게 생깁니 까? 어떤 한계가 있을까요? 리플렉션 코드를 제거하면 자신이 찾은 한계로 인해 생활 할 수없는 것일 수 있습니다. 가능한 경우 또는 대안이 바람직한지 확인하기 위해 리플렉션없이이 코드를 설계하는 것이 좋습니다.

5

반사가 느립니다. 리플렉션으로 메소드를 호출하는 것은 일반적인 방법보다 약 3 배 느립니다. 이 작업을 한 번만 또는 심각하지 않은 상황에서 수행하면 아무런 문제가 없습니다. 시간 결정적 방법으로 10'000 배를 사용한다면 구현을 변경하는 것이 좋습니다.

+0

사실 인 경우이 진술을 정말 좋아합니다. "리플렉션으로 메소드를 호출하는 것은 정상적인 방법보다 약 3 배 느립니다." 참조가 있으십니까? –

+0

내 게시물은 약 3 세입니다.이 정보가있는 곳에서 기억할 수 없습니다. – Enyra

+0

FieldInfo 및 PropertyInfo GetValue SetValue에서 데이터 액세스 계층을 컴파일 된 표현식으로 변환했습니다. 40 개의 열로 30,000 개의 행을 읽는 데 걸리는 시간은 4 초에서 1 초로 줄어 들었습니다. 그러나, side-by-side 비교에서, reflection은 값을 설정하고 가져올 때 컴파일 된 표현식보다 200 ~ 250 배 느립니다. – Loathing

16

비 반사 코드와 비교할 때 속도가 느립니다. 중요한 것은 느리지 만 느린 경우 으로 계산됩니다. 예를 들어 웹 환경에서 리플렉션을 사용하여 객체를 인스턴스화하면 예상되는 Concurency가 최대 10K까지 올라갈 수 있습니다.

어쨌든 사전에 성능에 대해 신경 쓰지 않아도됩니다. 일들이 느린 것으로 밝혀지면, 앞으로 계획 한 부분이 최적화를 필요로하는 부분을 현지화 할 수 있도록 올바르게 설계하면 속도를 늘릴 수 있습니다. 나는 IOC의와 함께 연주하기 시작 때까지 내가 somethign 비슷한 일을했다

Dynamic... But Fast: The Tale of Three Monkeys, A Wolf and the DynamicMethod and ILGenerator Classes

+1

URL이 변경된 것으로 보입니다. 이제 다음 주소에서 확인할 수 있습니다. http://www.codeproject.com/Articles/19513/Dynamic-But-Fast-The-Tale-of-Three-Monkeys-A- Wolf – GrandMasterFlush

0

: 당신이 속도를 필요로하는 경우

당신은이 유명한 기사를 확인할 수 있습니다. 스프링, 객체 정의를 사용하여 SQL, XML 또는 Mock과 같은 데이터 공급자를 지정합니다!

+0

Spring.net은 런타임에 의존성을 상당히 업데이트 할 수 있습니다. 구성 파일을 업데이트하고 공장에서 인스턴스를 다시로드하면 업데이트 된 인스턴스에 대한 참조를 얻게됩니다. (별도의 스프링 XML 파일을 사용하는 경우에만 app.config에서 구성을로드하면이 기능이 작동하지 않습니다. – Jacob

2

나는 느린 반사가없는 것과 어떻게 비교되는지를 보여주기 위해 빠른 테스트를 할 것이라고 생각했습니다.반사

  • 총 시간을 그 속성들 각각을 반복과 일치하여 58 객체 인스턴스화 함께

    : 52,254 나노초

    while (reader.Read()) { 
        string[] columns = reader.CurrentRecord; 
        CdsRawPayfileEntry toAdd = new CdsRawPayfileEntry(); 
        IEnumerable<PropertyInfo> rawPayFileAttributes = typeof(CdsRawPayfileEntry).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(CustomIndexAttribute))); 
        foreach (var property in rawPayFileAttributes) { 
         int propertyIndex = ((CustomIndexAttribute)property.GetCustomAttribute(typeof(CustomIndexAttribute))).Index; 
         if (propertyIndex < columns.Length) 
          property.SetValue(toReturn, columns[propertyIndex]); 
         else 
          break; 
        } 
    } 
    

반사없이

  • 는 새로운 객체를
  • 총 시간을 만들어 58 개체 인스턴스화 : 868 나노초이기는하지만

    while (reader2.Read()) { 
         string[] columns = reader2.CurrentRecord; 
         CdsRawPayfileEntry toAdd = new CdsRawPayfileEntry() { 
          ColumnZero = columns[0], 
          ColumnOne = columns[1], 
          ColumnTwo = columns[2], 
          ColumnThree = columns[3], 
          ColumnFour = columns[4], 
          ColumnFive = columns[5], 
          ColumnSix = columns[6], 
          ColumnSeven = columns[7], 
          ColumnEight = columns[8], 
          ColumnNine = columns[9], 
          ColumnTen = columns[10], 
          ColumnEleven = columns[11], 
          ColumnTwelve = columns[12], 
          ColumnThirteen = columns[13], 
          ColumnFourteen = columns[14], 
          ColumnFifteen = columns[15], 
          ColumnSixteen = columns[16], 
          ColumnSeventeen = columns[17] 
         }; 
        } 
    

, 반사도 검색해야하기 때문에 완전히 공평하지 리플렉션을 통해 새 오브젝트를 생성하는 것 위에 모든 속성의 특정 속성이 58 * 18 번이지만 최소한 일부 시각을 제공합니다.

관련 문제