Почему Unity использует отражение, чтобы получить метод обновления?
12
Почему Unity использовать отражение для того , чтобы доступ к MonoBehaviourметодам сообщения , как Awake, Update, Start, ...?
Разве это не будет медленно использовать отражение? Почему он не использует другие подходы, как Template Method? Он может просто определить методы как абстрактные в MonoBehaviourбазовом классе и заставить подклассы реализовать его.
Нет, Unity не использует System.Reflection для поиска магического метода каждый раз, когда ему нужно вызвать его.
Вместо этого, при первом обращении к MonoBehaviour заданного типа базовый сценарий проверяется во время выполнения сценария (Mono или IL2CPP), определены ли у него какие-либо магические методы, и эта информация кэшируется. Если у MonoBehaviour есть определенный метод, он добавляется в соответствующий список, например, если в сценарии определен метод Update, он добавляется в список сценариев, которые необходимо обновлять каждый кадр.
Во время игры Unity просто перебирает эти списки и выполняет из нее методы - это просто. Кроме того, именно поэтому не имеет значения, является ли ваш метод обновления общедоступным или закрытым.
Что касается причин, по которым это делается таким образом, я буду в значительной степени отсылать вас (читателя) к ответу Д.М. Грегори , который сводится к балансу двух конкурирующих вещей:
Оптимизация производительности
Простота использования нового разработчика
Новый разработчик просто хочет, чтобы он работал, и не хочет выяснять, «как мне подключить это к системе событий?» но он все равно должен работать быстро с минимальными накладными расходами.
Решение, вероятно, является лучшим, которое может быть достигнуто в рамках этих двух ограничений. Или, по крайней мере, лучшее, что команда разработчиков Unity смогла придумать в то время. Возможно, мы никогда не узнаем.
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 для своих проектов, который давно занимается этой оптимизацией. Я просто хотел получить подтверждение, что оно все еще нужно / полезно.
Одним из преимуществ системы, используемой Unity, является то, что вам не нужно реализовывать каждое сообщение MonoBehaviour, из которых более 60 .
Обычно нам просто нужен один или несколько таких методов. Поскольку некоторые специфичны для физики 2D / 3D, некоторые уникальны для камер или систем частиц, маловероятно, что какой-либо один скрипт когда-либо будет нуждаться в них всех.
Оставляя сообщения, которые нам не нужны, как невыполненные, мы можем четко сигнализировать среде выполнения «даже не беспокойтесь о вызове OnCollisionStay2D для этого объекта - мне это не нужно»
Это может быть существенным выигрышем в эффективности. Теперь движок может отфильтровать короткий список для вызова обновления только для ~ 20 объектов в моей сцене, для которых требуется настраиваемая логика обновления в каждом кадре, и не для всех ~ 200 объектов, которые составляют все пейзажи или реагируют только на физические события.
источник