Leistungsunterschiede beim Vergleichen von Symbolen und Zeichenfolgen


7

In sx.eleinem Fall müssen wir überprüfen, ob wir bestanden haben GEToder POSTals Argument.

Derzeit wird das Argument als Zeichenfolge übergeben und (string= "GET" url-method)zum Vergleichen verwendet "GET".

Gibt es einen Vorteil der Elisp / Byte-Kompilierung, wenn Sie es in ein Symbol ändern (equal url-method 'GET)?


Unabhängig von der Geschwindigkeit sind Symbole in Lisp für diesen Zweck idiomatisch. Verwenden Sie außerdem, um eqmit einem Symbol zu vergleichen.

eqkonvertiert Emacs-Objekte in intund vergleicht sie. Der Vergleich von ints ist viel schneller als der Vergleich von strings.
Abo-Abo

1
string=funktioniert wie erwartet, unabhängig davon, ob url-methodes sich um ein Symbol oder eine Zeichenfolge handelt. OTOH Wenn Sie eqoder verwenden equal, müssen Sie sicherstellen, dass die Argumente vom gleichen Typ sind.
YoungFrog

Antworten:


11

Neue Benutzer von Lisp, die aus anderen Sprachen stammen, verwenden manchmal aus Gewohnheit Zeichenfolgen für solche Zwecke.

Symbole können mit eqstatt nur verglichen werden equal. string=verwendet Code ähnlich wie equal, um jedes Zeichen zu testen, bis eine Nichtübereinstimmung gefunden wird. Der Symbolvergleich kann also etwas schneller sein. Wenn Sie den Vergleich beispielsweise in einer Schleife verwenden, kann der Unterschied von Bedeutung sein.

Abhängig vom jeweiligen Code kann es außerdem häufig einfacher oder lesbarer sein, Symbole anstelle von Zeichenfolgen zu verwenden. Und es gibt Funktionen (und Makros usw.), die Symbole erwarten oder die Dinge standardmäßig mit eq(oder eql) vergleichen . Um diese mit Zeichenfolgen zu verwenden, müssen Sie ohnehin in Symbole konvertieren.


7

Beachten Sie, dass der Lisp-Reader Symbole interniert , sodass unabhängige Verweise auf ein bestimmtes Symbol genau dasselbe Lisp-Objekt ergeben und Sie sie folglich vergleichen können eq(wobei nur die Objektadressen verglichen werden müssen).

Umgekehrt sind unabhängige Zeichenfolgen immer unterschiedliche Lisp-Objekte , und daher müssen Sie deren Inhalt vergleichen.

Sie würden daher erwarten, dass der eqVergleich für die Leistung gewinnt.

Merkwürdigerweise (ich bin auf jeden Fall sehr überrascht), einige triviale Tests mit benchmark-runschenkt string=den Sieg durch eine ganze Marge. Das kommt mir sehr merkwürdig vor. YMMV?


Bearbeiten: Also habe ich diese Antwort (und ihren Kommentar) gerade wieder bemerkt und mich inspiriert gefühlt, um zu sehen, ob ich das Ergebnis neu erstellen und erklären kann.

nb Zunächst wird nichts bytekompiliert.

Die erste Erkenntnis war, dass meine Symbole quoted waren und die Zeichenfolgen nicht, und ich stellte sofort fest, dass das quotefür den Großteil des Geschwindigkeitsunterschieds verantwortlich war:

(benchmark-run 10000000
  (string= "foo" "foo"))

ist für kleinere Saiten durchweg schneller als:

(benchmark-run 10000000
  (eq 'foo 'foo))

Wenn wir jedoch auch die Zeichenfolge zitieren:

(benchmark-run 10000000
  (string= '"foo" '"foo"))

das gleicht die Dinge fast vollständig aus.

Im Durchschnitt scheint der Saitenvergleich jedoch immer noch um ein Haar zu gewinnen , es sei denn, die Saite ist ziemlich groß .

Ein alternativer Ansatz besteht darin, die Objekte an Variablen zu binden:

(let ((foo 'test)
      (bar 'test))
  (benchmark-run 10000000
    (eq foo bar)))

(let ((foo "test")
      (bar "test"))
  (benchmark-run 10000000
    (string= foo bar)))

Wieder sehe ich den Saitenvergleich im Durchschnitt schneller durch eine Nase.

Nach der Byte-Kompilierung sehe ich nur ein konsistentes Ergebnis für die let-gebundenen Variablenfälle, bei denen eqes konsistent schneller ist als string=(ungefähr 2/3 der Zeit).

Bei den anderen Beispielen erhalte ich (für mich) unsinnige Ergebnisse, da die zitierten Zeichenfolgen schneller sind als die nicht zitierten Zeichenfolgen, was ich nur vermuten kann, ist effektiv Rauschen von anderen Aspekten der Ausführung und / oder von sich benchmark-runselbst. Es gab genug Abwechslung zwischen verschiedenen Läufen derselben Funktion, um Unterschiede zwischen Läufen verschiedener Funktionen vollständig zu verschleiern.


Meine Schlussfolgerungen sind:

(a) eqVergleiche mit einem Symbol können (etwas kontraintuitiv) langsamer sein als ein Zeichenfolgenvergleich, wenn das Symbol in Anführungszeichen steht.

(b) Wenn die Saiten nicht ziemlich groß sind, sind die praktischen Unterschiede völlig vernachlässigbar, und deshalb würde ich mich aus rein leistungsbezogenen Gründen nicht darum kümmern, eine in die andere umzuwandeln.


3
Vielleicht , weil die Art und Weisen Sie Ihren Test eingerichtet haben bewirkt , dass jedes Symbol von neuem in jedem Durchlauf der Schleife erzeugt werden, so dass Sie Lochfraß intern+ eqgegen string=. Oder möglicherweise aus einem ganz anderen Grund: Es ist unmöglich zu sagen, ohne Ihren Code zu sehen. Sie sollten Ihren Testcode als Frage auf dieser Site veröffentlichen.
Gilles 'SO - hör auf böse zu sein'

Ich habe versucht, benchmark-run-compiled(mit der Idee, dass das die Kosten von entfernen würde intern), aber mehrmals negative Ergebniszeiten erhalten. Ich denke, beide Operationen sind zu schnell, um zuverlässig zu messen.
Npostavs
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.