Почему Unity использует отражение, чтобы получить метод обновления?


12

Почему Unity использовать отражение для того , чтобы доступ к MonoBehaviourметодам сообщения , как Awake, Update, Start, ...?

Разве это не будет медленно использовать отражение? Почему он не использует другие подходы, как Template Method? Он может просто определить методы как абстрактные в MonoBehaviourбазовом классе и заставить подклассы реализовать его.

Ответы:


20

Это не

Как называется обновление

Нет, Unity не использует System.Reflection для поиска магического метода каждый раз, когда ему нужно вызвать его.

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

Во время игры Unity просто перебирает эти списки и выполняет из нее методы - это просто. Кроме того, именно поэтому не имеет значения, является ли ваш метод обновления общедоступным или закрытым.

Что касается причин, по которым это делается таким образом, я буду в значительной степени отсылать вас (читателя) к ответу Д.М. Грегори , который сводится к балансу двух конкурирующих вещей:

  1. Оптимизация производительности
  2. Простота использования нового разработчика

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

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


2
tl; dr тот же процесс, другой, более быстрый API. Но почему они не выбрали другой метод, предложенный ОП?
— Wondra

10
Мы не должны отрицать возможность простой старой причины "плохого дизайна". После выхода с # исходным кодом пользователей обнаружили тонны ошибок и необъяснимых проектных решений. Некоторые геймдевы наконец смогли понять эти неожиданные поведения, с которыми они боролись годами.
— Exerion

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

6
Там также могут быть исторические причины для этого дизайна. Unity начинали с собственного языка сценариев, который они постепенно вытесняли в пользу C #. Вполне естественно, что они хотели продолжать использовать одни и те же шаблоны, даже если это означало немного обмануть.
— Филипп

3
Я думаю, что мы можем с пользой ответить на вопрос «Чего Unity выполняет таким способом» - например. в чем преимущество коллекции абстрактных открытых методов, которые должны быть реализованы. Мы не можем ответить "о чем думали разработчики Unity?" но мы можем решить, "почему этот подход полезен для пользователей движка?"
— DMGregory

10

Он может просто определить методы как абстрактные в базовом классе MonoBehaviour и заставить подклассы реализовать его.

Одним из преимуществ системы, используемой Unity, является то, что вам не нужно реализовывать каждое сообщение MonoBehaviour, из которых более 60 .

Обычно нам просто нужен один или несколько таких методов. Поскольку некоторые специфичны для физики 2D / 3D, некоторые уникальны для камер или систем частиц, маловероятно, что какой-либо один скрипт когда-либо будет нуждаться в них всех.

Оставляя сообщения, которые нам не нужны, как невыполненные, мы можем четко сигнализировать среде выполнения «даже не беспокойтесь о вызове OnCollisionStay2D для этого объекта - мне это не нужно»

Это может быть существенным выигрышем в эффективности. Теперь движок может отфильтровать короткий список для вызова обновления только для ~ 20 объектов в моей сцене, для которых требуется настраиваемая логика обновления в каждом кадре, и не для всех ~ 200 объектов, которые составляют все пейзажи или реагируют только на физические события.


Просто вопрос ... насколько я знаю (не лично), если у вас есть тысячи GameObjects, каждый из которых использует скрипт с методом Update, вы оказываете значительное влияние на производительность. Альтернатива состоит в том, чтобы использовать списки и перебирать их, используя только один метод Update в скрипте менеджера, что, по-видимому, значительно более эффективно. Это все еще так, или это уже изменилось? - Если ничего не изменилось, это означало бы, что способ Unity сделать это далеко не оптимален в отношении производительности.
— Битва

4
@ То, что вы описываете, согласуется со ссылкой, которую Draco18s цитирует с 2015 года, и я подозреваю, что это все еще верно. Возможность оставить метод Update неопределенным для этих тысяч объектов - это именно то, что позволяет этой оптимизации работать. Если бы у каждого MonoBehaviour был метод Update, определенный через абстрактный базовый класс, как описано в разделе вопроса, который я цитировал, то у нас не было бы возможности ограничить наши вызовы обновления только итерацией списка менеджера. Обратите внимание, что эти вопросы и ответы не затрагивают вопрос «Является ли подход Unity оптимальным?» но только как нынешний подход может принести пользу.
— DMGregory

Ну я вижу, это имеет смысл. Спасибо за ответ!
— битва

@Battle Это все еще правда. В то время как Unity более производительна, чем альтернативы, она по-прежнему требует больше ресурсов, чем обычный вызов функции.
— Draco18s больше не доверяет SE

@ Draco18s - Да. Я уже внедрил UpdateManager для своих проектов, который давно занимается этой оптимизацией. Я просто хотел получить подтверждение, что оно все еще нужно / полезно.
— битва
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.