mirror of
https://github.com/metosin/reitit.git
synced 2025-12-18 08:51:12 +00:00
Much faster without transients
This commit is contained in:
parent
81b9bdceef
commit
659aac7fd0
4 changed files with 12 additions and 17 deletions
|
|
@ -3,7 +3,6 @@ package reitit;
|
||||||
// https://www.codeproject.com/Tips/1190293/Iteration-Over-Java-Collections-with-High-Performa
|
// https://www.codeproject.com/Tips/1190293/Iteration-Over-Java-Collections-with-High-Performa
|
||||||
|
|
||||||
import clojure.lang.IPersistentMap;
|
import clojure.lang.IPersistentMap;
|
||||||
import clojure.lang.ITransientMap;
|
|
||||||
import clojure.lang.Keyword;
|
import clojure.lang.Keyword;
|
||||||
import clojure.lang.PersistentArrayMap;
|
import clojure.lang.PersistentArrayMap;
|
||||||
|
|
||||||
|
|
@ -35,26 +34,20 @@ public class Trie {
|
||||||
case '+':
|
case '+':
|
||||||
hasPlus = true;
|
hasPlus = true;
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return decode(chars, begin, end, hasPercent, hasPlus);
|
return decode(chars, begin, end, hasPercent, hasPlus);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Match {
|
public static class Match {
|
||||||
final ITransientMap params = PersistentArrayMap.EMPTY.asTransient();
|
public IPersistentMap params = PersistentArrayMap.EMPTY;
|
||||||
public Object data;
|
public Object data;
|
||||||
|
|
||||||
public IPersistentMap parameters() {
|
|
||||||
return params.persistent();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
Map<Object, Object> m = new HashMap<>();
|
Map<Object, Object> m = new HashMap<>();
|
||||||
m.put(Keyword.intern("data"), data);
|
m.put(Keyword.intern("data"), data);
|
||||||
m.put(Keyword.intern("params"), parameters());
|
m.put(Keyword.intern("params"), params);
|
||||||
return m.toString();
|
return m.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -165,8 +158,6 @@ public class Trie {
|
||||||
@Override
|
@Override
|
||||||
public Match match(int i, int max, char[] path, Match match) {
|
public Match match(int i, int max, char[] path, Match match) {
|
||||||
if (i < max && path[i] != end) {
|
if (i < max && path[i] != end) {
|
||||||
boolean hasPercent = false;
|
|
||||||
boolean hasPlus = false;
|
|
||||||
int stop = max;
|
int stop = max;
|
||||||
for (int j = i; j < max; j++) {
|
for (int j = i; j < max; j++) {
|
||||||
final char c = path[j];
|
final char c = path[j];
|
||||||
|
|
@ -174,12 +165,10 @@ public class Trie {
|
||||||
stop = j;
|
stop = j;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
hasPercent = hasPercent || c == '%';
|
|
||||||
hasPlus = hasPlus || c == '+';
|
|
||||||
}
|
}
|
||||||
final Match m = child.match(stop, max, path, match);
|
final Match m = child.match(stop, max, path, match);
|
||||||
if (m != null) {
|
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;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
@ -218,7 +207,7 @@ public class Trie {
|
||||||
@Override
|
@Override
|
||||||
public Match match(int i, int max, char[] path, Match match) {
|
public Match match(int i, int max, char[] path, Match match) {
|
||||||
if (i < max) {
|
if (i < max) {
|
||||||
match.params.assoc(parameter, decode(path, i, max));
|
match.params = match.params.assoc(parameter, decode(path, i, max));
|
||||||
match.data = data;
|
match.data = data;
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,7 @@
|
||||||
|
|
||||||
(defn lookup [matcher path]
|
(defn lookup [matcher path]
|
||||||
#?(:clj (if-let [match ^Trie$Match (Trie/lookup ^Trie$Matcher matcher ^String 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)]
|
:cljs (if-let [match (match matcher 0 (count path) path)]
|
||||||
(let [params (if-let [path-params (:path-params match)]
|
(let [params (if-let [path-params (:path-params match)]
|
||||||
(persistent! path-params)
|
(persistent! path-params)
|
||||||
|
|
|
||||||
|
|
@ -348,6 +348,7 @@
|
||||||
;; 64µs (trie-router, no injects, optimized) - 124µs (clojure)
|
;; 64µs (trie-router, no injects, optimized) - 124µs (clojure)
|
||||||
;; 63µs (trie-router, no injects, switch-case) - 124µs (clojure)
|
;; 63µs (trie-router, no injects, switch-case) - 124µs (clojure)
|
||||||
;; 63ns (trie-router, no injects, direct-data)
|
;; 63ns (trie-router, no injects, direct-data)
|
||||||
|
;; 54ns (trie-router, non-transient params)
|
||||||
(let [requests (mapv route->req routes)]
|
(let [requests (mapv route->req routes)]
|
||||||
(title "all")
|
(title "all")
|
||||||
(cc/quick-bench
|
(cc/quick-bench
|
||||||
|
|
|
||||||
|
|
@ -572,6 +572,7 @@
|
||||||
;; 326ns (java-segment-router)
|
;; 326ns (java-segment-router)
|
||||||
;; 194ns (trie)
|
;; 194ns (trie)
|
||||||
;; 160ns (trie, prioritized)
|
;; 160ns (trie, prioritized)
|
||||||
|
;; 130ns (trie, non-transient, direct-data)
|
||||||
(b! "reitit" reitit-f)
|
(b! "reitit" reitit-f)
|
||||||
|
|
||||||
;; 2845ns
|
;; 2845ns
|
||||||
|
|
@ -585,16 +586,18 @@
|
||||||
;; 373ns (trie)
|
;; 373ns (trie)
|
||||||
;; 323ns (trie, prioritized)
|
;; 323ns (trie, prioritized)
|
||||||
;; 289ns (trie, prioritized, zero-copy)
|
;; 289ns (trie, prioritized, zero-copy)
|
||||||
|
;; 266ns (trie, non-transient, direct-data)
|
||||||
(b! "reitit-ring" reitit-ring-f)
|
(b! "reitit-ring" reitit-ring-f)
|
||||||
|
|
||||||
;; 385ns (java-segment-router, no injects)
|
;; 385ns (java-segment-router, no injects)
|
||||||
;; 271ms (trie)
|
;; 271ms (trie)
|
||||||
;; 240ns (trie, prioritized)
|
;; 240ns (trie, prioritized)
|
||||||
|
;; 214ns (trie, non-transient, direct-data)
|
||||||
(b! "reitit-ring-fast" reitit-ring-fast-f)
|
(b! "reitit-ring-fast" reitit-ring-fast-f)
|
||||||
;; 240ns (trie, prioritized, zero-copy)
|
|
||||||
|
|
||||||
;; 2553ns (linear-router)
|
;; 2553ns (linear-router)
|
||||||
;; 630ns (segment-router-backed)
|
;; 630ns (segment-router-backed)
|
||||||
|
;; 464ns (trie, non-transient, direct-data)
|
||||||
(b! "reitit-ring-linear" reitit-ring-linear-f)
|
(b! "reitit-ring-linear" reitit-ring-linear-f)
|
||||||
|
|
||||||
;; 2137ns
|
;; 2137ns
|
||||||
|
|
@ -627,6 +630,7 @@
|
||||||
;; 629ms (arraylist)
|
;; 629ms (arraylist)
|
||||||
;; 409ns (transient)
|
;; 409ns (transient)
|
||||||
;; 409ns (staticMultiMatcher)
|
;; 409ns (staticMultiMatcher)
|
||||||
|
;; 305ns (non-persistent-params)
|
||||||
(let [app (ring/ring-handler (ring/router opensensors-routes) {:inject-match? false, :inject-router? false})
|
(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}]
|
request {:uri "/v1/users/1/devices/1", :request-method :get}]
|
||||||
(doseq [[p r] (-> app (ring/get-router) (r/routes))]
|
(doseq [[p r] (-> app (ring/get-router) (r/routes))]
|
||||||
|
|
@ -638,6 +642,7 @@
|
||||||
(prof/start {})
|
(prof/start {})
|
||||||
; "Elapsed time: 9183.657012 msecs"
|
; "Elapsed time: 9183.657012 msecs"
|
||||||
; "Elapsed time: 8674.70132 msecs"
|
; "Elapsed time: 8674.70132 msecs"
|
||||||
|
; "Elapsed time: 6714.434915 msecs"
|
||||||
(time
|
(time
|
||||||
(dotimes [_ 20000000]
|
(dotimes [_ 20000000]
|
||||||
(app request)))
|
(app request)))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue