Much faster without transients

This commit is contained in:
Tommi Reiman 2019-02-09 15:05:31 +02:00
parent 81b9bdceef
commit 659aac7fd0
4 changed files with 12 additions and 17 deletions

View file

@ -3,7 +3,6 @@ package reitit;
// https://www.codeproject.com/Tips/1190293/Iteration-Over-Java-Collections-with-High-Performa
import clojure.lang.IPersistentMap;
import clojure.lang.ITransientMap;
import clojure.lang.Keyword;
import clojure.lang.PersistentArrayMap;
@ -35,26 +34,20 @@ public class Trie {
case '+':
hasPlus = true;
break;
default:
break;
}
}
return decode(chars, begin, end, hasPercent, hasPlus);
}
public static class Match {
final ITransientMap params = PersistentArrayMap.EMPTY.asTransient();
public IPersistentMap params = PersistentArrayMap.EMPTY;
public Object data;
public IPersistentMap parameters() {
return params.persistent();
}
@Override
public String toString() {
Map<Object, Object> m = new HashMap<>();
m.put(Keyword.intern("data"), data);
m.put(Keyword.intern("params"), parameters());
m.put(Keyword.intern("params"), params);
return m.toString();
}
}
@ -165,8 +158,6 @@ public class Trie {
@Override
public Match match(int i, int max, char[] path, Match match) {
if (i < max && path[i] != end) {
boolean hasPercent = false;
boolean hasPlus = false;
int stop = max;
for (int j = i; j < max; j++) {
final char c = path[j];
@ -174,12 +165,10 @@ public class Trie {
stop = j;
break;
}
hasPercent = hasPercent || c == '%';
hasPlus = hasPlus || c == '+';
}
final Match m = child.match(stop, max, path, match);
if (m != null) {
m.params.assoc(key, decode(path, i, stop, hasPercent, hasPlus));
m.params = m.params.assoc(key, decode(path, i, stop));
}
return m;
}
@ -218,7 +207,7 @@ public class Trie {
@Override
public Match match(int i, int max, char[] path, Match match) {
if (i < max) {
match.params.assoc(parameter, decode(path, i, max));
match.params = match.params.assoc(parameter, decode(path, i, max));
match.data = data;
return match;
}

View file

@ -226,7 +226,7 @@
(defn lookup [matcher path]
#?(:clj (if-let [match ^Trie$Match (Trie/lookup ^Trie$Matcher matcher ^String path)]
(->Match (.data match) (.parameters match)))
(->Match (.data match) (.params match)))
:cljs (if-let [match (match matcher 0 (count path) path)]
(let [params (if-let [path-params (:path-params match)]
(persistent! path-params)

View file

@ -348,6 +348,7 @@
;; 64µs (trie-router, no injects, optimized) - 124µs (clojure)
;; 63µs (trie-router, no injects, switch-case) - 124µs (clojure)
;; 63ns (trie-router, no injects, direct-data)
;; 54ns (trie-router, non-transient params)
(let [requests (mapv route->req routes)]
(title "all")
(cc/quick-bench

View file

@ -572,6 +572,7 @@
;; 326ns (java-segment-router)
;; 194ns (trie)
;; 160ns (trie, prioritized)
;; 130ns (trie, non-transient, direct-data)
(b! "reitit" reitit-f)
;; 2845ns
@ -585,16 +586,18 @@
;; 373ns (trie)
;; 323ns (trie, prioritized)
;; 289ns (trie, prioritized, zero-copy)
;; 266ns (trie, non-transient, direct-data)
(b! "reitit-ring" reitit-ring-f)
;; 385ns (java-segment-router, no injects)
;; 271ms (trie)
;; 240ns (trie, prioritized)
;; 214ns (trie, non-transient, direct-data)
(b! "reitit-ring-fast" reitit-ring-fast-f)
;; 240ns (trie, prioritized, zero-copy)
;; 2553ns (linear-router)
;; 630ns (segment-router-backed)
;; 464ns (trie, non-transient, direct-data)
(b! "reitit-ring-linear" reitit-ring-linear-f)
;; 2137ns
@ -627,6 +630,7 @@
;; 629ms (arraylist)
;; 409ns (transient)
;; 409ns (staticMultiMatcher)
;; 305ns (non-persistent-params)
(let [app (ring/ring-handler (ring/router opensensors-routes) {:inject-match? false, :inject-router? false})
request {:uri "/v1/users/1/devices/1", :request-method :get}]
(doseq [[p r] (-> app (ring/get-router) (r/routes))]
@ -638,6 +642,7 @@
(prof/start {})
; "Elapsed time: 9183.657012 msecs"
; "Elapsed time: 8674.70132 msecs"
; "Elapsed time: 6714.434915 msecs"
(time
(dotimes [_ 20000000]
(app request)))