2009-11-17 2 views
0

У меня есть структура, которая позволяет пользователям делать запросы к определенному источнику данных (игровая база данных Football Manager 2010 для тех, кто вас интересует).Как это сделать быстро?

В этом контексте у меня есть два разных режима, в которых может работать мой фрейм: режим реального времени и режим кэширования. Я хочу, чтобы пользователи, которые используют эту инфраструктуру, могли переключаться, просто вызвав другой конструктор (например, 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), 63 мс очень разумно, учитывая большое количество объектов.

Но! В 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 мс, более чем в 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

То, что больше всего времени проводилось в моей собственности getter, не очень полезная информация. –

ответ

1

Вместо того чтобы создавать свой контекст, используя new Context(Mode.Cached)), есть фабричный метод, который создает контекст. Затем реализуйте свои два поведения в двух разных классах, которые разделяют все, что им нужно, для абстрактного супер-типа. Используйте аспекты и размышления для решения проблем, которые не имеют простого прямого решения.


заменить

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

с

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

PlayerAttrs, где есть оператор Int16, чтобы преобразовать себя Int16 по требованию, имеет смещение требуется, и выполняет соответствующую кэшированные/не- кэшированный поиск.

+0

Да, я действительно подумал об этом, но на данный момент существует около 400 объектов, разделенных более чем 10 классами. Каждое свойство ведет себя одинаково: выполните вызов ProcessManager.ReadFromBuffer с байтом [] объекта, смещение, которое находится в его атрибуте, и тип. Для другого режима что-то похожее. Мне кажется, что кодовое ткачество должно быть идеальным для этого, так как в противном случае мне пришлось бы копировать один и тот же код 400 раз. –

+0

Хорошо. Ваш представленный пример кода кажется действительно хорошей идеей. Будет реализовывать это. –

1
  1. метод использования CompileTimeValidate, чтобы проверить, если его свойство или не
+0

Ну, это всегда свойство, поскольку я применяю атрибут только к свойствам. Проверка на ~ получение, есть, потому что у меня также есть разные настройки поведения для двух режимов, как бы я их разделял? –

+0

Тем не менее вы можете переместить оператор if и строку по сравнению с CompileTimeValidate и сохранить результат в собственном атрибуте bool этого аспекта. – 2009-11-18 16:17:41

+0

Прохладный, отрезанный на 70%, используя это –

0

Отражение может быть дорогостоящим. Одна вещь, которую вы можете попробовать, это на самом деле компиляция обертки для этого класса во время выполнения и сохранение себя за каждый звонок, который у вас есть.

+0

Я не занимаюсь отражением –

2

Вы можете получить гораздо лучшие результаты, используя PostSharp 2.0 LocationInterceptionAspect.

Но тогда вам следует избегать использования eventArgs.Method.ReturnType во время выполнения; скорее получите значение в методе RuntimeInitialize и сохраните его в поле. Поэтому System.Reflection не используется во время выполнения.

+0

А, я думал, что eventArgs.Method.ReturnType был просто полем, созданным во время компиляции, и не использовался для отражения !? –

Смежные вопросы