1. Этот сайт использует файлы cookie. Продолжая пользоваться данным сайтом, Вы соглашаетесь на использование нами Ваших файлов cookie. Узнать больше.
  2. Вы находитесь в сообществе Rubukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на различные языки плагины наших коллег из других стран.
    Скрыть объявление
Скрыть объявление
В преддверии глобального обновления, мы проводим исследования, которые помогут нам сделать опыт пользования форумом ещё удобнее. Помогите нам, примите участие!

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

Тема в разделе "Разработка плагинов для новичков", создана пользователем CoolBoy, 4 фев 2017.

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

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

    Баллы:
    96
    Имя в Minecraft:
    Xezard
    Всех приветствую в данной теме.

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

    Теперь к сути:
    Имею класс 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
    Код:
    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
    Код:
    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 был переделан, теперь содержит лишь статические методы, которые собирают инвентарь "на ходу".
     
    Последнее редактирование: 6 фев 2017
  2. AtomicInteger

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    Баллы:
    96
    Имя в Minecraft:
    Xezard
    Yep. Вот только за ArrayList и настучать по голове можно.
    HashSet.
    Я понял, использую, спасибо.

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

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

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

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

    Баллы:
    96
    Имя в Minecraft:
    Xezard
    http://developer.alexanderklimov.ru/android/java/set.php

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

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

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

    Dereku Старожил Пользователь

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

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

    Баллы:
    96
    Имя в Minecraft:
    Xezard
    Не понял чтот совсем. В чём смысл то?
    Во время исполнения команды "собирать" инвентарь не создавая ни каких обьектов, типа CharacterGUI?
     
  14. Dereku

    Dereku Старожил Пользователь

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

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

    Баллы:
    96
    Имя в Minecraft:
    Xezard
    Мммм. Большое спасибо, за совет :)
     
  16. Exception_Prototype

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

    Баллы:
    96
  17. Dereku

    Dereku Старожил Пользователь

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

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

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

    Dereku Старожил Пользователь

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

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

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

Поделиться этой страницей