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

  • Автор темы Автор темы 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
Java:
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
Java:
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 был переделан, теперь содержит лишь статические методы, которые собирают инвентарь "на ходу".
 
Последнее редактирование:
Как минимум, я думаю, можно упростить Task.Создать всего 1 шедулер и в нём обрабатывать динамический список игроков.При входе/выходе обновлять список.
Из того, что мне уже предлагали:
-
"Запускай один шедулер отправляющий актионбар всем игрокам."
Не выйдет. Во-первых, перебор игроков циклом довольно ресурсозатратен, так как, насколько мне известно, при Bukkit.getOnlinePlayers() - создаётся новый лист с игроками. Во-вторых, перебор игроков займёт продолжительное время, если их будет больше 100. Поэтому - не вариант.
Нет, я имел в виду не getOnlinePlayers, а некоторый список(Array, List etc), который будет изменятся двумя ивентами: PlayerJoinEvent and PlayerQuitEvent.Конечно, вариант не самый хороший, но как минимум, мне кажется, лучше чем 500 шедулеров.И ещё, зачем запускать 2 BukkitRunnable'a в отдельном потоке?
 
Как минимум, я думаю, можно упростить Task.Создать всего 1 шедулер и в нём обрабатывать динамический список игроков.При входе/выходе обновлять список.

Нет, я имел в виду не getOnlinePlayers, а некоторый список(Array, List etc), который будет изменятся двумя ивентами: PlayerJoinEvent and PlayerQuitEvent.Конечно, вариант не самый хороший, но как минимум, мне кажется, лучше чем 500 шедулеров.И ещё, зачем запускать 2 BukkitRunnable'a в отдельном потоке?
У меня уже имеется HashSet<EPlayer> который при входе принимает игрока и при выходе убирает его оттуда. Но в чём разница, что Bukkit.geyOnlinePlayers вернёт мне 500 плееров, что EPlayerManager.getEPlayer() вернёт мне 500 екземпляров EPlayer, из которых я смогу достать игрока?

Насчёт 2 баккит раннаблов в отдельном потоке - а что, у вас есть идея лучше? Это мой самый оптимальный вариант, на данный момент.
 
Раз уж подняли эту тему с getOnlinePlayers, то объясни раз и навсегда. Почему эта штука грузит и как избежать нагрузки? Так как я лично часто использую данный метод, но всё чаще и чаще вижу посты, где говорится о том, что этот метод нагружает.
 
Раз уж подняли эту тему с getOnlinePlayers, то объясни раз и навсегда. Почему эта штука грузит и как избежать нагрузки? Так как я лично часто использую данный метод, но всё чаще и чаще вижу посты, где говорится о том, что этот метод нагружает.
Я сам в эту тему особо не вникал. Скажем так, во время вызова метода, то ли коллекция, то ли аррайлист, то ли массив создаётся, со всеми игроками онлайн. Насчёт нагрузки - цикл на проход 500 игроков и так затрачивает достаточно времени. Самая плохое - от кода, исполняемого в теле цикла. Чем его там больше и чем он сложнее, тем больше времени затрачивается на прохождение цикла.

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

Кто знает больше - поправляйте :)
Отличие в том, что на каждый вызов метода getOnlinePlayers() формируется список из всех игроков(что бы он совпадал с действительным количеством игроков) и возвращается, и уже по нему проходит цикл.А я предлагал создать список, который не формируется каждую секунду, а лишь при двух ивентах(Входе игрока и выходе), и то, не с нуля, а обновление существующего.И уже тогда, в шедулере, осуществляется проход по этому массиву.В итоге, в теле шедулера уменьшается количество кода, а именно, мы выигрываем 1 операцию - формирование списка игроков с нуля.
 
Хорошо, допустим есть ArrayList<Player>.
Если я буду помещать и удалять с этого списка игроков при входе и выходе с сервера и брать его как "Список онлайн игроков", то такой подход будет являться действующем?
 
Хорошо, допустим есть ArrayList<Player>.
Если я буду помещать и удалять с этого списка игроков при входе и выходе с сервера и брать его как "Список онлайн игроков", то такой подход будет являться действующем?
Yep. Вот только за ArrayList и настучать по голове можно.
HashSet.
Отличие в том, что на каждый вызов метода getOnlinePlayers() формируется список из всех игроков(что бы он совпадал с действительным количеством игроков) и возвращается, и уже по нему проходит цикл.А я предлагал создать список, который не формируется каждую секунду, а лишь при двух ивентах(Входе игрока и выходе), и то, не с нуля, а обновление существующего.И уже тогда, в шедулере, осуществляется проход по этому массиву.В итоге, в теле шедулера уменьшается количество кода, а именно, мы выигрываем 1 операцию - формирование списка игроков с нуля.
Я понял, использую, спасибо.

Ещё предложения?
 
Yep. Вот только за ArrayList и настучать по голове можно.
HashSet.

Я понял, использую, спасибо.

Ещё предложения?
Ээээ...не надо по голове.
Я лично для хранения определённого количества блоков и кастомных команд использую ArrayList.
А что с ним не так? Ибо если там всё плохо, надо бы перейди на HashMap
 
Ээээ...не надо по голове.
Я лично для хранения определённого количества блоков и кастомных команд использую ArrayList.
А что с ним не так? Ибо если там всё плохо, надо бы перейди на HashMap
http://developer.alexanderklimov.ru/android/java/set.php

HashSet более оптимизирован и хранит только уникальные обьекты.
 
Yep. Вот только за ArrayList и настучать по голове можно.
HashSet.

Я понял, использую, спасибо.

Ещё предложения?
Класс Task имплементирует Runnable, из-за чего нужно переопределять метод run, в котором ты создаешь 2 BukkitRunnable'a, которые в свою очередь имплементируют Runnable и перегружают метод run.Получается матрешка.Я бы не стал наследовать Runnable в классе Task и запускал бы 2 BukkitRunnable'a в конструкторе, например.Я не уверен, что такой вариант будет работать, но попытаться избавится от наследования Runnable в классе Task ты можешь.
 
Создавай Inventoy только тогда, кода надо.
Ну и один раннабл вместо двух. Меньше действий по запуску/остановке.
 
Создавай Inventoy только тогда, кода надо.
Не понял чтот совсем. В чём смысл то?
Во время исполнения команды "собирать" инвентарь не создавая ни каких обьектов, типа CharacterGUI?
 
http://developer.alexanderklimov.ru/android/java/set.php

HashSet более оптимизирован и хранит только уникальные обьекты.
heart.gif
 
Не, разницы на 50 игроках не видна будет, но на 500 будет заметно (немножко).
Вообще я бы создал где то 500-1000 объектов EPlayer и смотрел бы, что где жмёт.
Планирую тесты провести ближе к завершению плагина. На данный момент даже 30% не написано.
Скорее всего и под скорборд тоже придётся шедулер делать. Уникальный для каждого.
 
Скорее всего и под скорборд тоже придётся шедулер делать. Уникальный для каждого.
Один шедулер на игрока. Я не думаю, что там будет что то ужасно объемное, что не сможет обработаться за 20ms.
 
Назад
Верх