XNA / C #: Entity Factories и typeof (T) производительность - PullRequest
4 голосов
/ 21 июля 2011

В нашей игре (предназначенной для мобильных устройств) у нас есть несколько различных типов сущностей, и я пишу фабрику / репозиторий для обработки экземпляров новых сущностей. Каждый конкретный тип сущности имеет собственную реализацию фабрики, и этими фабриками управляет EntityRepository.

Я бы хотел реализовать хранилище как таковое:

Repository
{
 private Dictionary <System.Type, IEntityFactory<IEntity>> factoryDict;

 public T CreateEntity<T> (params) where T : IEntity
 {
      return factoryDict[typeof(T)].CreateEntity() as T;
 }
}

пример использования

var enemy = repo.CreateEntity<Enemy>();

но я обеспокоен производительностью, особенно связанной с операцией typeof (T) в приведенном выше. Насколько я понимаю, компилятор не сможет определить тип T, и его нужно будет определить во время выполнения с помощью отражения, правильно? Один из вариантов:

Repository
{
 private Dictionary <System.Type, IEntityFactory> factoryDict;

 public IEntity CreateEntity (System.Type type, params)
 {
      return factoryDict[type].CreateEntity();
 }
}

, который будет использоваться как

var enemy = (Enemy)repo.CreateEntity(typeof(Enemy), params);

в этом случае всякий раз, когда вызывается typeof (), тип находится под рукой и может быть определен компилятором (верно?), И производительность должна быть лучше. Будет ли заметная разница? какие-либо другие соображения? Я знаю, что у меня также может быть такой метод, как CreateEnemy, в хранилище (у нас есть только несколько типов сущностей), который был бы быстрее, но я бы предпочел, чтобы хранилище было как можно не осведомленным о сущностях.

EDIT:

Я знаю, что это, скорее всего, не является узким местом, я беспокоюсь только о том, что это такая трата, чтобы тратить время на размышления, когда есть немного менее засахаренная альтернатива. И я думаю, что это интересный вопрос:)

Я провел несколько сравнительных тестов, которые оказались весьма интересными (и которые, кажется, подтверждают мои первоначальные подозрения).

Использование инструмента измерения производительности, который я нашел на http://blogs.msdn.com/b/vancem/archive/2006/09/21/765648.aspx (который запускает метод тестирования несколько раз и отображает такие показатели, как среднее время и т. д.) Я провел базовый тест, тестирование:

private static T GenFunc<T>() where T : class 
    {

        return dict[typeof(T)] as T;
    }

против

    private static Object ParamFunc(System.Type type)
    {
        var d = dict[type];
        return d;
    }

называется

str = GenFunc<string>();

против

str = (String)ParamFunc(typeof(String));

соответственно. Paramfunc демонстрирует значительное улучшение производительности (выполняется в среднем на 60-70% за время, затрачиваемое на GenFunc), но тест довольно прост, и я могу упустить некоторые вещи. В частности, как приведение типов выполняется в универсальной функции.

Интересно отметить, что при «кэшировании» типа в переменной и его передаче в ParamFunc с использованием typeof () каждый раз достигается небольшая (незначительная) производительность.

Ответы [ 2 ]

6 голосов
/ 21 июля 2011

Обобщения в C # не используют или не нуждаются в отражении.

Внутренние типы передаются как RuntimeTypeHandle значения.И оператор typeof отображается на Type.GetTypeFromHandle ( MSDN ).Не смотря на проверку Rotor или Mono, я ожидал бы, что GetTypeFromHandle будет O (1) и очень быстрым (например, поиск по массиву).

Так что в общем случае (<T>) вы 'по сути, передаем RuntimeTypeHandle в ваш метод и вызываем GetTypeFromHandle в вашего метода.В не универсальном случае вы сначала вызываете GetTypeFromHandle, а затем передаете результирующий Type в ваш метод.Производительность должна быть примерно одинаковой - и в значительной степени перевешиваться другими факторами, как и любые места, которые вы выделяете память (например: если вы используете ключевое слово params).

Но в любом случае это фабричный метод.Конечно, он не будет вызываться чаще, чем пару раз в секунду?Стоит ли даже оптимизировать?

1 голос
/ 21 июля 2011

Вы всегда слышите, насколько медленное отражение, но в C # на самом деле быстрое отражение и медленное отражение. typeof - быстрое отражение - в основном это накладные расходы на вызов метода, что почти бесконечно мало.

Я бы поспорил на ужин с бифштексами и лобстерами, что это не будет узким местом для производительности вашего приложения, так что даже попытка его оптимизации даже не стоит вашего (или нашего) времени. Об этом говорили миллион раз, но стоит повторить: «Преждевременная оптимизация - корень всего зла».

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


Кроме того, мой комментарий выше стоит повторить, так что вы не тратите больше времени на повторное изобретение колеса: Любой приличный контейнер IoC (такой как AutoFac) может [создавать фабричные методы] автоматически. Если вы используете один из них, вам не нужно писать свой собственный репозиторий, или писать собственные методы CreateEntity(), или даже вызывать метод CreateEntity() самостоятельно - библиотека сделает все это за вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...