Является ли неизменность и Flex плохим сочетанием? - PullRequest
3 голосов
/ 08 февраля 2010

В моей маленькой флекс-фреймворке, построенном с нуля, я определил класс ThreeDPoint, который содержит координаты x, y и z для отслеживания моих внутриигровых объектов, называемых актерами. Я также использую класс для создания векторов движения, которые складываются и складываются вместе в каждом кадре, чтобы создать кумулятивный вектор движения для каждого актера.

Я сделал класс ThreeDPoint неизменным, чтобы поддержать идею о том, что данная позиция не может быть изменена, вы можете только дать Актеру новую позицию, а также отговорить потенциальных клиентских программистов (меня!) От изменения векторов движения в стек, а не выделение нового вектора движения для создания того типа движения, который вам нужен.

К сожалению, производительность в этой системе падает очень быстро. Используя профилировщик Flex Builder, я отмечаю, что у меня есть утечка некоторых объектов ThreeDPoint (у меня есть 26 действующих лиц, у меня, вероятно, должно быть около 30, но всего за 60 секунд времени выполнения у меня получается более 1000 таких объектов), но поскольку настолько легки, фактический объем памяти довольно постоянен.

С другой стороны, профилировщик показывает более 250 000 объектов ThreeDPoint, созданных кумулятивно после 60 секунд времени выполнения. Теперь, будучи тем, как я намеренно создаю и выбрасываю эти объекты, мне это не кажется странным. Но единственное, что приходит на ум при просмотре такого профиля, это то, что огромное количество вызовов new () и GC (нет, я не вызываю GC явно) убивает производительность, особенно с учетом того факта, что когда я начал, и ThreeDPoint был изменчив, все было хорошо. Это кажется разумным?

package net.emptykingdom.utils
{
    public class ThreeDPoint
    {
        public function ThreeDPoint(x:Number = 0, y:Number = 0, z:Number = 0)
        {
            this._x = x;
            this._y = y;
            this._z = z;
        }

        public function get X():Number { return _x; }
        public function get Y():Number { return _y; }
        public function get Z():Number { return _z; }

        private var _x:Number = 0;
        private var _y:Number = 0;
        private var _z:Number = 0;
    }
}

РЕДАКТИРОВАТЬ: Я обнаружил и удалил утечку памяти. Это привело к небольшому, но заметному усилению перфекта, хотя и не так велико, чтобы можно было создавать значительно большее число актеров. Согласно профилировщику, в моем коде по-прежнему преобладают вызовы конструктора ThreeDPoint. Возвращение к изменчивому ThreeDPoint вернуло мне немного производительности, которой я когда-то наслаждался. Поэтому я предполагаю, что создание экземпляров объектов Flex обходится дороже, чем в других средах, в которых я играл. Слишком плохо.

Ответы [ 3 ]

4 голосов
/ 08 февраля 2010

Ваше описание очень интересное, и ваше подозрение - что предварительная оптимизация, сделав класс ThreeDPoint неизменным, разрушил вашу производительность, - звучит правильно. Вы в основном заменяете изменение внутренностей объекта (изменяемого) заменой всего объекта, и предполагаете, что gc и время выполнения понравится больше. Как вы сказали, инстанциации и gc вызовы - вот то, что склеивает дела сейчас. Таким образом, у вас есть только несколько возможностей:

  1. Вы где-то держитесь за ссылки или создаете гораздо больше этих объектов, чем хотите, и это убивает вашу производительность
  2. Сокращая количество срабатываний gc, вы сможете повысить производительность. Я сомневаюсь в этом, но, по крайней мере, вы можете попробовать .
  3. Изменчивый дизайн был лучше. Не в теории, но движок Flash видит это так.

Если эта проблема вам действительно интересна, сократите ее до основных элементов (изменяемых и неизменяемых, множества созданных объектов и мутаций) и продемонстрируйте свои догадки в некоторых тестовых прогонах. Затем опубликуйте результаты здесь, чтобы мы могли быть умнее.

Мой догадываюсь : это явный случай попытки сделать одолжение для Flash Engine, которые не помогают.

Редактировать: Читая ваш первый абзац лучше, я понимаю, что вы делаете это по причинам дизайна в вашей программе. Если это так, то, к сожалению, программирование в реальном времени - это когда ОО-проектирование соответствует суровой реальности движка.

2 голосов
/ 08 февраля 2010

Вы создаете 160 ThreeDPoints за актера в секунду. при 30 кадрах в секунду это примерно 5 на актера на кадр. Это делает 15 вызовов на каждого субъекта на кадр только для считывания координат ThreeDPoints. Я считаю, что это не может масштабироваться бесконечно.

Что плохого в Actor::moveTo(x:Number, y:Number, z:Number):void и Actor::moveBy(x:Number, y:Number, z:Number):void?

Кроме того, для игры, я думаю, это гораздо лучшая модель для актера (просто эскиз):

package {
    public class Actor {
        private var _x:Number;
        private var _y:Number;
        private var _z:Number;
        public var xs:Number;
        public var ys:Number;
        public var zs:Number;

        public function Actor() {}
        public function get x():Number { return _x; }
        public function get y():Number { return _y; }
        public function get z():Number { return _z; }
        public function step():void {
            this.x += this.xs;
            this.y += this.ys;
            this.z += this.zs;
        }                  
    }   
}

следующий интерфейс описывает все воздействия на актера (такие силы как трение, гравитация, тяга и т. Д.).

package {
    interface IActorAffector {
        function applyTo(actor:Actor):void;
    }   
}

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

неизменность не так уж плоха, но в вашем случае она кажется слишком дорогой. Кроме того, если вы хорошо управляете ThreeDPoints, вы можете использовать пул объектов, чтобы поддерживать инстанцирование и низкий уровень GC.

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

0 голосов
/ 08 февраля 2010

Я бы сказал, что использование неизменяемых значений для представления быстро меняющихся значений в чувствительном к производительности приложении в AS3 - плохая смесь, да. AS3 - не самая быстрая среда, и работать с ней в 3D означает снижение производительности. Просьба создать новый объект для каждого изменения в значении примитива, вероятно, вызывает проблемы.

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