Хостинг серверов Minecraft playvds.com
  1. Вы находитесь в русском сообществе Bukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на русский язык плагины наших собратьев из других стран.
    Dismiss Notice

Помогите Оптимизация

Discussion in 'Разработка плагинов для новичков' started by CoolBoy, Feb 4, 2017.

  1. Автор темы
    CoolBoy

    CoolBoy Активный участник Пользователь

    Trophy Points:
    96
    Skype:
    thecoolboy2070
    Имя в Minecraft:
    CoolBoy
    Всех приветствую в данной теме.

    Ниже - "многа букав".
    Я постарался обьяснить всё максимально понятно. Если всё же не понятно - покиньте тред.

    Теперь к сути:
    Имею класс EPlayer, новый экземпляр которого создаётся каждый раз при входе нового игрока.
    Сам класс имеет около 15 полей, типа int и double.
    При инициализации класса EPlayer, создаётся также 2 новых экземпляра классов CharacterGUI и Task.
    CharacterGUI создаёт Inventory, с нужными ItemStack внутри, на которых отображаются поля класса EPlayer. Тоесть, под каждого EPlayer, свой, уникальный CharacterGUI.
    Task - implements Runnable.
    В методе run() я запускаю 2 асинхронных BukkitRunnable(),
    один из которых постоянно прибавляет некоторое значение к одному из полей EPlayer каждую секунду - 20 тиков.
    Второй отправляет обычному Player актионбар, в котором также выводятся некоторые данные полей EPlayer.
    И так, на одного активного плеера на сервере мы имеем:
    1 экземпляр класса EPlayer.
    1 экземпляр класса CharacterGUI.
    1 экземпляр класса Task.
    2 асинхронных BukkitTask'а.

    Теперь вопрос, какой может быть нагрузка при 100 игроках? 200? 500???

    1000 асинхронных BukkitTask'ов - на 500 игроков, до таких масштабов, до этого, я, увы, ещё не доходил.

    Вобщем, вопрос, господа:
    Возможно ли хоть как-то оптимизировать весь этот код? Если да, то каким образом всё это можно оптимизировать по максимуму?
    Часть кода прикладываю:
    Task.class
    Code:
    public class Task
    implements Runnable
    {
        private BukkitTask action_bar_task;
        private BukkitTask mana_regen_task;
    
        private EPlayer eplayer;
    
        public Task(EPlayer eplayer)
        {
            this.eplayer = eplayer;
    
            TaskManager.getTasks().add(this);
        }
    
        public void stopAllTasks()
        {
            this.action_bar_task.cancel();
            this.mana_regen_task.cancel();
        }
    
        public void stopManaRegenTask()
        {
            this.mana_regen_task.cancel();
        }
    
        public BukkitTask getManaRegenTask()
        {
            return this.mana_regen_task;
        }
    
        public void stopActionBarTask()
        {
            this.action_bar_task.cancel();
        }
    
        public BukkitTask getActionBarTask()
        {
            return this.action_bar_task;
        }
    
        public EPlayer getEPlayer()
        {
            return this.eplayer;
        }
    
        @Override
        public void run()
        {
            this.mana_regen_task = new BukkitRunnable()
            {
                public void run()
                {
                    if (eplayer.getPlayer() != null)
                    {
                        if (eplayer.getMana() < eplayer.getMaxMana())
                        {
                            eplayer.addMana(eplayer.getManaRegen());
                        }
                    }
                }
            }.runTaskTimerAsynchronously(Core.getCore(), 0, Constants.MANA_REGEN_TIME * 20);
        
            this.action_bar_task = new BukkitRunnable()
            {
                public void run()
                {
                    if (eplayer.getPlayer() != null)
                    {
                        TitleUtils.sendActionBar(eplayer.getPlayer(),
                    ChatColor.translateAlternateColorCodes('&', StringUtils.replaceActionBarMessage(Constants.ACTION_BAR_MESSAGE,  (Double) Math.floor(eplayer.getPlayer().getHealth() * 100) / 100.0, eplayer.getPlayer().getMaxHealth(),
    (Double) Math.floor(eplayer.getMana() * 100) / 100.0, eplayer.getMaxMana())));
                    }
                }
            }.runTaskTimerAsynchronously(Core.getCore(), 0, 13);
        }
    }
    
    EPlayer.class
    Code:
    public class EPlayer
    {
        private String name;
    
        private Inventory inventory;
    
        //private doubles and ints
    
        public EPlayer(Player player)
        {
            this.name = player.getName();
    
            this.inventory = new CharacterGUI(this);
    
            new Task(this).run();
        }
    
        //Getters, setters, some other void methods
    }
    
    Решено.
    Шедулер с ActionBar запускаю один, на всех онлайн игроков. Получаю онлайн игроков из своего же HashSet<EPlayer>, куда игроки попадают при входе и удаляются при выходе.
    CharacterGUI был переделан, теперь содержит лишь статические методы, которые собирают инвентарь "на ходу".
     
    Last edited: Feb 6, 2017
  2. Хостинг MineCraft
    <
  3. AtomicInteger

    AtomicInteger Активный участник Пользователь

    Trophy Points:
    46
    Как минимум, я думаю, можно упростить Task.Создать всего 1 шедулер и в нём обрабатывать динамический список игроков.При входе/выходе обновлять список.[DOUBLEPOST=1486204049,1486202654][/DOUBLEPOST]
    Нет, я имел в виду не getOnlinePlayers, а некоторый список(Array, List etc), который будет изменятся двумя ивентами: PlayerJoinEvent and PlayerQuitEvent.Конечно, вариант не самый хороший, но как минимум, мне кажется, лучше чем 500 шедулеров.И ещё, зачем запускать 2 BukkitRunnable'a в отдельном потоке?
     
  4. Автор темы
    CoolBoy

    CoolBoy Активный участник Пользователь

    Trophy Points:
    96
    Skype:
    thecoolboy2070
    Имя в Minecraft:
    CoolBoy
    У меня уже имеется HashSet<EPlayer> который при входе принимает игрока и при выходе убирает его оттуда. Но в чём разница, что Bukkit.geyOnlinePlayers вернёт мне 500 плееров, что EPlayerManager.getEPlayer() вернёт мне 500 екземпляров EPlayer, из которых я смогу достать игрока?

    Насчёт 2 баккит раннаблов в отдельном потоке - а что, у вас есть идея лучше? Это мой самый оптимальный вариант, на данный момент.
     
  5. Exception_Prototype

    Exception_Prototype Активный участник Пользователь

    Trophy Points:
    46
    Раз уж подняли эту тему с getOnlinePlayers, то объясни раз и навсегда. Почему эта штука грузит и как избежать нагрузки? Так как я лично часто использую данный метод, но всё чаще и чаще вижу посты, где говорится о том, что этот метод нагружает.
     
  6. Автор темы
    CoolBoy

    CoolBoy Активный участник Пользователь

    Trophy Points:
    96
    Skype:
    thecoolboy2070
    Имя в Minecraft:
    CoolBoy
    Я сам в эту тему особо не вникал. Скажем так, во время вызова метода, то ли коллекция, то ли аррайлист, то ли массив создаётся, со всеми игроками онлайн. Насчёт нагрузки - цикл на проход 500 игроков и так затрачивает достаточно времени. Самая плохое - от кода, исполняемого в теле цикла. Чем его там больше и чем он сложнее, тем больше времени затрачивается на прохождение цикла.

    Кто знает больше - поправляйте :)
     
  7. AtomicInteger

    AtomicInteger Активный участник Пользователь

    Trophy Points:
    46
    Отличие в том, что на каждый вызов метода getOnlinePlayers() формируется список из всех игроков(что бы он совпадал с действительным количеством игроков) и возвращается, и уже по нему проходит цикл.А я предлагал создать список, который не формируется каждую секунду, а лишь при двух ивентах(Входе игрока и выходе), и то, не с нуля, а обновление существующего.И уже тогда, в шедулере, осуществляется проход по этому массиву.В итоге, в теле шедулера уменьшается количество кода, а именно, мы выигрываем 1 операцию - формирование списка игроков с нуля.
     
  8. Exception_Prototype

    Exception_Prototype Активный участник Пользователь

    Trophy Points:
    46
    Хорошо, допустим есть ArrayList<Player>.
    Если я буду помещать и удалять с этого списка игроков при входе и выходе с сервера и брать его как "Список онлайн игроков", то такой подход будет являться действующем?
     
  9. Автор темы
    CoolBoy

    CoolBoy Активный участник Пользователь

    Trophy Points:
    96
    Skype:
    thecoolboy2070
    Имя в Minecraft:
    CoolBoy
    Yep. Вот только за ArrayList и настучать по голове можно.
    HashSet.[DOUBLEPOST=1486206690,1486206626][/DOUBLEPOST]
    Я понял, использую, спасибо.

    Ещё предложения?
     
  10. Exception_Prototype

    Exception_Prototype Активный участник Пользователь

    Trophy Points:
    46
    Ээээ...не надо по голове.
    Я лично для хранения определённого количества блоков и кастомных команд использую ArrayList.
    А что с ним не так? Ибо если там всё плохо, надо бы перейди на HashMap
     
  11. Автор темы
    CoolBoy

    CoolBoy Активный участник Пользователь

    Trophy Points:
    96
    Skype:
    thecoolboy2070
    Имя в Minecraft:
    CoolBoy
    http://developer.alexanderklimov.ru/android/java/set.php

    HashSet более оптимизирован и хранит только уникальные обьекты.
     
  12. AtomicInteger

    AtomicInteger Активный участник Пользователь

    Trophy Points:
    46
    Класс Task имплементирует Runnable, из-за чего нужно переопределять метод run, в котором ты создаешь 2 BukkitRunnable'a, которые в свою очередь имплементируют Runnable и перегружают метод run.Получается матрешка.Я бы не стал наследовать Runnable в классе Task и запускал бы 2 BukkitRunnable'a в конструкторе, например.Я не уверен, что такой вариант будет работать, но попытаться избавится от наследования Runnable в классе Task ты можешь.
     
  13. Dereku

    Dereku Старожил

    Trophy Points:
    173
    Skype:
    derek_unavailable
    Имя в Minecraft:
    _Dereku
    Создавай Inventoy только тогда, кода надо.
    Ну и один раннабл вместо двух. Меньше действий по запуску/остановке.
     
  14. Автор темы
    CoolBoy

    CoolBoy Активный участник Пользователь

    Trophy Points:
    96
    Skype:
    thecoolboy2070
    Имя в Minecraft:
    CoolBoy
    Не понял чтот совсем. В чём смысл то?
    Во время исполнения команды "собирать" инвентарь не создавая ни каких обьектов, типа CharacterGUI?
     
  15. Dereku

    Dereku Старожил

    Trophy Points:
    173
    Skype:
    derek_unavailable
    Имя в Minecraft:
    _Dereku
    Ну да. На производительности так себе скажется, зато память спасибо может сказать.
     
  16. Автор темы
    CoolBoy

    CoolBoy Активный участник Пользователь

    Trophy Points:
    96
    Skype:
    thecoolboy2070
    Имя в Minecraft:
    CoolBoy
    Мммм. Большое спасибо, за совет :)
     
  17. Exception_Prototype

    Exception_Prototype Активный участник Пользователь

    Trophy Points:
    46
  18. Dereku

    Dereku Старожил

    Trophy Points:
    173
    Skype:
    derek_unavailable
    Имя в Minecraft:
    _Dereku
    Не, разницы на 50 игроках не видна будет, но на 500 будет заметно (немножко).
    Вообще я бы создал где то 500-1000 объектов EPlayer и смотрел бы, что где жмёт.
     
  19. Автор темы
    CoolBoy

    CoolBoy Активный участник Пользователь

    Trophy Points:
    96
    Skype:
    thecoolboy2070
    Имя в Minecraft:
    CoolBoy
    Планирую тесты провести ближе к завершению плагина. На данный момент даже 30% не написано.
    Скорее всего и под скорборд тоже придётся шедулер делать. Уникальный для каждого.
     
  20. Dereku

    Dereku Старожил

    Trophy Points:
    173
    Skype:
    derek_unavailable
    Имя в Minecraft:
    _Dereku
    Один шедулер на игрока. Я не думаю, что там будет что то ужасно объемное, что не сможет обработаться за 20ms.
     
  21. Exception_Prototype

    Exception_Prototype Активный участник Пользователь

    Trophy Points:
    46
    А всё же, что лучше хранить и проверять ники игроков или сам объект Player ? Я понял что он там проверяет через хэш, но всё же.
     

Share This Page