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()) {

2つの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ループはもうありません

私の悪い、十分に注意を払っていませんでした...

しかし、考え方は同じです。ハッシュマップ/ハッシュセットを使用する場合は、反復するのではなく、常に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 に答える