2009-11-17 2 views
0

사용자가 특정 데이터 소스 (관심있는 사람들을 위해 Football Manager 2010 ingame 데이터베이스)에 쿼리 할 수있는 프레임 워크가 있습니다.이걸 어떻게 빨리 얻을 수 있습니까?

이 프레임 워크에서는 프레임 워크를 실행할 수있는 두 가지 모드 인 실시간 및 캐시 모드가 있습니다. 이 프레임 워크를 사용하는 사용자가 다른 생성자 (예 : new Context(Mode.Cached))를 호출하여 전환 할 수 있기를 바랍니다. 사용자가해야하는 유일한 스위치 여야합니다. 그래서 그는 여전히 모든 Linq 호출을 가질 수 있지만, 응용 프로그램이 더 적합 할 때 캐시 모드를 사용하십시오. 명확한.

나는 결정했다 그 때문에 PostSharp 내 최선의 선택을해야한다 사용 :

  • 은 우리가 있는지 확인 모든 재산에 측면 (즉, 이미 속성에 의해 장식 된 것)이 측면에서
  • 만들기 Cached 또는 Realtime 모드
  • 반환 값 중 하나를 메모리에서 또는 작동 캐시

음에서. 그러나! 속도가 충분하지 않습니다. 일을 할 때 90.000 개체에 대해 다음

foreach (Player p in fm.Players) 
{ 
    int ca = (short)ProcessManager.ReadFromBuffer(p.OriginalBytes, PlayerOffsets.Ca, typeof(Int16)); 
} 

그것은 단지 63 밀리합니다. (ReadFromBuffer는 byte[], int, Type을 가져와 object을 반환하는 매우 최적화 된 함수입니다.) 많은 양의 객체를 고려할 때 63ms가 매우 적당합니다.

하지만! PostSharp에서, 나는이를 사용하여 완전히 동일 구현 :

public override void OnInvocation(MethodInvocationEventArgs eventArgs) 
    { 
     if (eventArgs.Method.Name.StartsWith("~get_")) 
     { 
      if (Global.DatabaseMode == DatabaseModeEnum.Cached) 
      { 
       byte[] buffer = ((BaseObject)eventArgs.Instance).OriginalBytes; 

       eventArgs.ReturnValue = 
         ProcessManager.ReadFromBuffer(buffer, this.Offset, eventArgs.Method.ReturnType); 
      } 

지금 나는이

foreach (Player p in fm.Players) 
{ 
    int ca = p.CA; 
} 

를 사용하여 그리고 그것은 많은 782 MS, 10 회 이상 소요 전화!

나는 같은 화면 생성 :

[Serializable] 
[MulticastAttributeUsage(MulticastTargets.Method, PersistMetaData = true)] 
internal class FMEntityAttribute : OnMethodInvocationAspect 
{ 
    public FMEntityAttribute(int offset, int additionalStringOffset) 
    { 
     this.Offset = offset; 
     this.AdditionalStringOffset = additionalStringOffset; 
    } 
    //blah blah AOP code 
} 

을 그리고 재산 내가이 잘 수행하기 위해 얻을 수있는 방법

[FMEntityAttribute(PlayerOffsets.Ca)] 
    public Int16 CA { get; set; } 

처럼 장식되어 있습니다!

+0

프로파일 링 작업에서 비싼 핫스팟이 무엇을 나타 냈습니까? –

+0

대부분의 시간이 내 재산 취득에 사용되었지만 실제로 유용한 정보는 아닙니다. –

답변

1

을 확인 컨텍스트를 생성하는 팩토리 메소드를 가지고있다. 그런 다음 추상적 인 수퍼 유형에 필요한 모든 것을 공유하는 두 개의 다른 클래스에서 두 가지 동작을 구현합니다. 간단한 직접 해결책이없는 문제를 해결하기 위해 측면과 반성을 사용하십시오.


대체

[FMEntityAttribute(PlayerOffsets.Ca)] public Int16 CA { get; } 

PlayerAttrs 디맨드 INT16 자체를 변환하는 연산자 INT16을 갖는다

public Int16 CA { get { return PlayerAttrs.Ca.Get(this); } } 

과 함께이 요구 오프셋을 가지며, 적절한 캐시 /은 비 수행 캐시 된 조회.

+0

예, 저는 그것에 대해 상당히 생각해 보았습니다 만,이 시점에서 약 10 개의 클래스로 분리 된 약 400 개의 속성이 있습니다. 모든 속성은 동일하게 동작합니다. 객체의 byte [], 속성에있는 오프셋 및 유형과 함께 ProcessManager.ReadFromBuffer를 호출합니다. 다른 모드에서는 비슷한 것입니다. 그렇지 않으면 필자는 동일한 코드를 400 번 붙여 넣어야 할 것입니다. –

+0

확인. 제공된 코드 예제는 정말 좋은 생각처럼 보입니다. 이것을 구현합니다. –

1
  1. 사용 CompileTimeValidate 방법은, 그 경우 속성 여부를 대신 new Context(Mode.Cached))를 사용하여 컨텍스트를 만드는
+0

속성에만 속성을 적용하기 때문에 항상 속성입니다. ~에 대한 확인은 두 가지 모드에 대한 다른 설정 동작을 가지고 있기 때문에 가능합니다. 어떻게 구분합니까? –

+0

if 문과 문자열을 CompileTimeValidate와 비교하고 결과를 aspect의 private bool 속성에 저장할 수 있습니다. –

+0

멋지다. 이것을 사용하여 70 %로 줄였습니다. –

0

반사가 비쌀 수 있습니다. 당신이 시도해 볼 수있는 한 가지 사실은 런타임에이 클래스에 대한 래퍼를 실제로 컴파일하고 현재 가지고있는 호출 당 히트를 저장하는 것입니다.

+0

리플렉션을 사용하고 있지 않습니다. –

2

PostSharp 2.0의 LocationInterceptionAspect를 사용하면 훨씬 더 좋은 결과를 얻을 수 있습니다.

하지만 런타임에 eventArgs.Method.ReturnType을 사용하지 않는 것이 좋습니다. RuntimeInitialize 메소드의 값을 가져 와서 필드에 저장하십시오. 따라서 System.Reflection은 런타임에 사용되지 않습니다.

+0

아, eventArgs.Method.ReturnType이 컴파일 타임에 생성 된 필드이고 리플렉션에 사용되지 않는다고 생각했습니다! –