Make the EventBus faster by avoiding Map#entrySet

This commit is contained in:
Vankka 2022-01-25 16:24:17 +02:00
parent 9662d9515f
commit 9cfaae7464
No known key found for this signature in database
GPG Key ID: 6E50CB7A29B96AD0
2 changed files with 49 additions and 40 deletions

View File

@ -53,6 +53,7 @@ public class EventBusImpl implements EventBus {
); );
private final Map<Object, List<EventListenerImpl>> listeners = new ConcurrentHashMap<>(); private final Map<Object, List<EventListenerImpl>> listeners = new ConcurrentHashMap<>();
private final List<EventListenerImpl> allListeners = new CopyOnWriteArrayList<>();
private final DiscordSRV discordSRV; private final DiscordSRV discordSRV;
private final Logger logger; private final Logger logger;
@ -76,7 +77,7 @@ public class EventBusImpl implements EventBus {
Class<?> currentClass = listenerClass; Class<?> currentClass = listenerClass;
do { do {
for (Method method : currentClass.getDeclaredMethods()) { for (Method method : currentClass.getDeclaredMethods()) {
checkMethod(listenerClass, method, suppressedMethods, methods, methodsByPriority); checkMethod(eventListener, listenerClass, method, suppressedMethods, methods, methodsByPriority);
} }
} while ((currentClass = currentClass.getSuperclass()) != null); } while ((currentClass = currentClass.getSuperclass()) != null);
@ -88,10 +89,11 @@ public class EventBusImpl implements EventBus {
} }
listeners.put(eventListener, methods); listeners.put(eventListener, methods);
allListeners.addAll(methods);
logger.debug("Listener " + eventListener.getClass().getName() + " subscribed"); logger.debug("Listener " + eventListener.getClass().getName() + " subscribed");
} }
private void checkMethod(Class<?> listenerClass, Method method, private void checkMethod(Object eventListener, Class<?> listenerClass, Method method,
List<Throwable> suppressedMethods, List<EventListenerImpl> methods, List<Throwable> suppressedMethods, List<EventListenerImpl> methods,
EnumMap<EventPriority, List<EventListenerImpl>> methodsByPriority) { EnumMap<EventPriority, List<EventListenerImpl>> methodsByPriority) {
Subscribe annotation = method.getAnnotation(Subscribe.class); Subscribe annotation = method.getAnnotation(Subscribe.class);
@ -140,7 +142,7 @@ public class EventBusImpl implements EventBus {
} }
EventPriority eventPriority = annotation.priority(); EventPriority eventPriority = annotation.priority();
EventListenerImpl listener = new EventListenerImpl(listenerClass, annotation, firstParameter, method); EventListenerImpl listener = new EventListenerImpl(eventListener, listenerClass, annotation, firstParameter, method);
methods.add(listener); methods.add(listener);
methodsByPriority.computeIfAbsent(eventPriority, key -> new CopyOnWriteArrayList<>()) methodsByPriority.computeIfAbsent(eventPriority, key -> new CopyOnWriteArrayList<>())
@ -154,9 +156,12 @@ public class EventBusImpl implements EventBus {
@Override @Override
public void unsubscribe(@NotNull Object eventListener) { public void unsubscribe(@NotNull Object eventListener) {
listeners.remove(eventListener); List<EventListenerImpl> removed = listeners.remove(eventListener);
if (removed != null) {
allListeners.removeAll(removed);
logger.debug("Listener " + eventListener.getClass().getName() + " unsubscribed"); logger.debug("Listener " + eventListener.getClass().getName() + " unsubscribed");
} }
}
@Override @Override
public void publish(@NotNull Event event) { public void publish(@NotNull Event event) {
@ -182,9 +187,7 @@ public class EventBusImpl implements EventBus {
Class<?> eventClass = event.getClass(); Class<?> eventClass = event.getClass();
for (EventPriority priority : EventPriority.values()) { for (EventPriority priority : EventPriority.values()) {
for (Map.Entry<Object, List<EventListenerImpl>> entry : listeners.entrySet()) { for (EventListenerImpl eventListener : allListeners) {
Object listener = entry.getKey();
for (EventListenerImpl eventListener : entry.getValue()) {
if (eventListener.isIgnoringCancelled() && event instanceof Cancellable && ((Cancellable) event).isCancelled()) { if (eventListener.isIgnoringCancelled() && event instanceof Cancellable && ((Cancellable) event).isCancelled()) {
continue; continue;
} }
@ -197,6 +200,7 @@ public class EventBusImpl implements EventBus {
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
try { try {
Object listener = eventListener.listener();
eventListener.method().invoke(listener, event); eventListener.method().invoke(listener, event);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
discordSRV.logger().error("Failed to access listener method: " + eventListener.methodName(), e); discordSRV.logger().error("Failed to access listener method: " + eventListener.methodName(), e);
@ -224,7 +228,6 @@ public class EventBusImpl implements EventBus {
} }
} }
} }
}
// Clear the states // Clear the states
for (Pair<Function<Object, Boolean>, ThreadLocal<EventListener>> state : STATES) { for (Pair<Function<Object, Boolean>, ThreadLocal<EventListener>> state : STATES) {

View File

@ -27,12 +27,14 @@ import java.lang.reflect.Method;
public class EventListenerImpl implements EventListener { public class EventListenerImpl implements EventListener {
private final Object listener;
private final Class<?> listenerClass; private final Class<?> listenerClass;
private final Subscribe annotation; private final Subscribe annotation;
private final Class<?> eventClass; private final Class<?> eventClass;
private final Method method; private final Method method;
public EventListenerImpl(Class<?> listenerClass, Subscribe annotation, Class<?> eventClass, Method method) { public EventListenerImpl(Object listener, Class<?> listenerClass, Subscribe annotation, Class<?> eventClass, Method method) {
this.listener = listener;
this.listenerClass = listenerClass; this.listenerClass = listenerClass;
this.annotation = annotation; this.annotation = annotation;
this.eventClass = eventClass; this.eventClass = eventClass;
@ -47,6 +49,10 @@ public class EventListenerImpl implements EventListener {
return annotation.priority(); return annotation.priority();
} }
public Object listener() {
return listener;
}
public Class<?> eventClass() { public Class<?> eventClass() {
return eventClass; return eventClass;
} }