2

我做了一个事件系统,但是太慢了。

问题是,我从未实际添加的地图中有多个条目。我不明白他们是如何到达那里的。

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);
            }
        }
    }
}
4

1 回答 1

3

您正在使用地图,因此请考虑使用其好处而不是迭代所有条目

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();
        }
    }
}
于 2012-07-27T21:19:41.907 回答