
FastEvent
Активный0.0
Установок
Последнее обновление
Версии
FastEvent
Проект закрыт
Кратко говоря, сама концепция оптимизации остаётся актуальной, но платформы Forge и NeoForge не разрешают модифицировать механизм регистрации событий – EventBus.
В отличие от базовых классов Minecraft или Forge, которые загружаются как составляющие самой игры, EventBus функционирует как внешняя библиотека. Из-за этого применять к нему инструменты трансформации кода наподобие Mixin или Transformer невозможно.
В экспериментальной версии 1.2.0 я предпринял попытку достичь ещё большего прироста производительности, применив нестандартный подход к изменению класса ASMEventHandler
. К сожалению, это решение оказалось нерабочим в версиях игры начиная с 1.18.2. Эти билды теперь сохранены в архиве и обновляться не будут.
Для чего создавался данный мод
FastEvent должен был стать оптимизирующим дополнением для Forge и NeoForge, радикально ускоряющим центральную систему обработки событий – основу Forge.
Скорость оптимизации: примеры тестов
Создать универсально подходящий тест для каждой поддерживаемой версии Minecraft чрезвычайно сложно, поскольку системы обработки событий в них значительно различаются. Для наглядности используем отчёт по бенчмарку JMH из открытого проекта Cleanroom, где применялся такой же техники скоростной оптимизации:
Зарегистрировано 10 000 обработчиков событий, отправлено 0 событий:
Benchmark Mode Cnt Score Error Units
BusPerformanceTest.register10000Legacy avgt 5 1126.498 ± 284.633 ms/op
BusPerformanceTest.register10000Modern avgt 5 1058.961 ± 173.586 ms/op
Прирост скорости составил около 6.4%.
Зарегистрировано 1 000 обработчиков событий, отправлено 10 000 событий:
Benchmark Mode Cnt Score Error Units
BusPerformanceTest.register1000test10000Legacy avgt 5 4407.963 ± 4250.643 ms/op
BusPerformanceTest.register1000test10000Modern avgt 5 3550.578 ± 1991.352 ms/op
Прирост скорости вырос до 24%.
Технические детали функционирования мода
Когда разработчики используют аннотации вроде @EventBusSubscriber
или @SubscribeEvent
для назначения обработчиков событий, EventBus не может получить прямой доступ к методу. Вместо этого он имеет лишь объект-дескриптор Method
. Наиболее простое решение – воспользоваться прямым вызовом через него: method.invoke(...)
. Виртуальная машина JVM интерпретирует этот вызов и передаёт управление в соответствующий метод, позволяя обработчику принять событие.
Однако method.invoke(...)
работает очень медленно. Для ускорения стандартный механизм EventBus генерирует во время работы игры новые специализированные классы под каждый метод-обработчик события. Это помогает избежать медленного вызова по рефлексии.
Но и генерация классов ощутимо замедляет работу. Решение, выбранное в FastEvent, – замена создания классов на операцию построения лямбда-выражений. Это быстрее конструирует обработчики событий. Дополнительным преимуществом является то, что лямбда остаётся «скрытой» для виртуальной машины, предоставляя JVM возможность применить дополнительные оптимизации.
Сравнение реализации наглядным кодом
class Listen {
public void onEvent(Event event) {
}
}
Listen lis = new Listen();
// Обычный подход Forge – создание класса под каждый обработчик
class IEventListener$Listen$onEvent implements IEventListener {
private Listen instance;
public IEventListener$Listen$onEvent(Listen instance) {
this.instance = instance;
}
@Override
public void invoke(Event event) {
instance.onEvent(event);
}
}
IEventListener handler = new IEventListener$Listen$onEvent(lis);
// Быстрая реализация через лямбду через FastEvent
IEventListener handler = lis::onEvent;