我制作了一个事件系统,但它太慢了。
问题是,地图中有多个我从未实际添加过的条目。我不明白他们是如何到达那里的。
public class OrdinalMap<V> {
private final Map<Integer, V> map;
public OrdinalMap(Class<? extends Enum<?>> valueType, V virginValue) {
map = new HashMap<Integer, V>();
Enum<?>[] enums = valueType.getEnumConstants();
for (int i = 0; i < enums.length; i++) {
put(enums[i].ordinal(), virginValue);
}
}
public OrdinalMap(Class<? extends Enum<?>> valueType) {
this(valueType, null);
}
public V put(Integer key, V value) {
return map.put(key, value);
}
public V get(Object o) {
return map.get(o);
}
public Set<Entry<Integer, V>> entrySet() {
return map.entrySet();
}
}
我想让 dispatchEvent 更快(减少迭代次数)。由于 registerListener
,它有太多的迭代次数在所有其他优先级中都有事件处理程序方法,当它们不应该存在时。我无法弄清楚为什么会有,但我确定它在 registerListener 中。因为它们在所有优先级内,我必须使用此检查: if(mapping.getKey()。getAnnotation(EventHandler.class).priority()。ordinal()== entry.getKey()){
这使得它更慢。
@Override
public void dispatchEvent(Event event) {
OrdinalMap<Map<Method, EventListener>> priorityMap = getRegistry().get(event.getClass());
if (priorityMap != null) {
CancellableEvent cancellableEvent = null;
boolean cancellable;
if (cancellable = event instanceof CancellableEvent) {
cancellableEvent = (CancellableEvent) event;
if (cancellableEvent.isCancelled()) return;
}
try {
for (Entry<Integer, Map<Method, EventListener>> entry : priorityMap.entrySet()) {
for (Entry<Method, EventListener> mapping : entry.getValue().entrySet()) {
if (mapping.getKey().getAnnotation(EventHandler.class).priority().ordinal() == entry.getKey()) {
mapping.getKey().invoke(mapping.getValue(), event);
if (cancellable && cancellableEvent.isCancelled()) return;
}
}
}
} catch (InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
@Override
public void registerListener(EventListener listener) {
for (Method method : listener.getClass().getMethods()) {
EventHandler handler = method.getAnnotation(EventHandler.class);
if (handler != null) {
Class<?>[] parameters = method.getParameterTypes();
if (parameters.length == 1) {
@SuppressWarnings("unchecked")
Class<? extends Event> event = (Class<? extends Event>) parameters[0];
EventPriority priority = handler.priority();
OrdinalMap<Map<Method, EventListener>> priorityMap = getRegistry().get(event);
if (priorityMap == null) {
priorityMap = new OrdinalMap<Map<Method, EventListener>>(EventPriority.class, (Map<Method, EventListener>) new HashMap<Method, EventListener>());
}
Map<Method, EventListener> methodMap = priorityMap.get(priority.ordinal());
methodMap.put(method, listener);
priorityMap.put(priority.ordinal(), methodMap);
getRegistry().put(event, priorityMap);
}
}
}
}
答案 0 :(得分:3)
您正在使用地图,因此请考虑使用thiere的好处,而不是迭代所有条目
if (mapping.getKey().getAnnotation(EventHandler.class).priority().ordinal() == entry.getKey()) {
比较两个hahmap键来找到匹配并不是一个好主意。
以下怎么样,我希望我没有犯错误
Set<Integer> priorityMapKeySet = priorityMap.keySet();
for (Map<Method, EventListener> mapping : priorityMap.values()) {
if (priorityMapKeySet.contains(mapping.getKey().getAnnotation(EventHandler.class).priority().ordinal())) {
mapping.getKey().invoke(mapping.getValue(), event);
if (cancellable && cancellableEvent.isCancelled()) return;
}
}
这里你不再拥有外部for循环
我的不好,没注意到......
但是这个想法是一样的,当使用hashmaps / hashsets时,应该总是尝试使用get / contains而不是迭代,并且为此需要设计注册表的方式使这个不可能
以下是否可以满足您的需求? (另)
private final static class Registry {
private final static Map<String, Set<Integer>> prioritySetByEventMap = new HashMap<>();
private final static Map<String, EventListener> eventListenerByEventAndPriorityMap = new HashMap<>();
private final static Map<String, Method> methodByEventAndListenerMap = new HashMap<>();
public static Set<Integer> getPrioritySetByEvent(Class<Event> event) {
return prioritySetByEventMap.get(event.getName());
}
public static synchronized void registerEventByPriority(Class<Event> event, Integer priority) {
Set<Integer> ps = prioritySetByEventMap.get(event.getName());
if(ps == null) {
ps = new HashSet<>();
prioritySetByEventMap.put(event.getName(), ps);
}
ps.add(priority);
}
public static EventListener getEventListenerByEventAndPriority(Class<Event> event, Integer priority) {
String key = event.getName() + "-" + priority;
return eventListenerByEventAndPriorityMap.get(key);
}
public static synchronized void registerEventListenerByEventAndPriority(Class<Event> event, Integer priority, EventListener listener) {
String key = event.getName() + "-" + priority;
eventListenerByEventAndPriorityMap.put(key, listener);
}
public static Method getMethodByEventAndListener(Class<Event> event, EventListener listener) {
String key = listener.toString() + "-" + event.getName();
return methodByEventAndListenerMap.get(key);
}
public static synchronized void registerMethodByEventAndListener(Class<Event> event, EventListener listener, Method method) {
String key = listener.toString() + "-" + event.getName();
methodByEventAndListenerMap.put(key, method);
}
}
和
public void registerListener(EventListener listener) {
for (Method method : listener.getClass().getMethods()) {
EventHandler handler = method.getAnnotation(EventHandler.class);
if (handler != null) {
Class<?>[] parameters = method.getParameterTypes();
if (parameters.length == 1) {
Class<Event> event = (Class<Event>) parameters[0];
EventPriority priority = handler.priority();
Registry.registerEventByPriority(event, priority.ordinal());
Registry.registerEventListenerByEventAndPriority(event, priority.ordinal(), listener);
Registry.registerMethodByEventAndListener(event, listener, method);
}
}
}
}
public void dispatchEvent(Event event) {
Set<Integer> prioritySet = Registry.getPrioritySetByEvent((Class<Event>) event.getClass());
if (prioritySet != null) {
CancellableEvent cancellableEvent = null;
boolean cancellable;
if (cancellable = event instanceof CancellableEvent) {
cancellableEvent = (CancellableEvent) event;
if (cancellableEvent.isCancelled())
return;
}
try {
for(Integer priority : prioritySet) {
EventListener listener = Registry.getEventListenerByEventAndPriority((Class<Event>) event.getClass(), priority);
if(listener != null) {
Method m = Registry.getMethodByEventAndListener((Class<Event>) event.getClass(), listener);
if(m != null) {
m.invoke(listener, event);
if (cancellable && cancellableEvent.isCancelled()) {
return;
}
}
}
}
} catch (InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
}
}