Der performanteste Weg zu prüfen, ob ein String leer ist (d. h. nur Leerzeichen enthält) in JavaScript?

8

Ich muss eine Funktion schreiben, die testet, wenn die angegebene Zeichenfolge "leer" ist, in dem Sinne, dass sie nur Leerzeichen enthält. Leerzeichen sind die folgenden:

%Vor%

Die Funktion wird oft aufgerufen, also muss sie wirklich, wirklich performant sein. Aber sollte nicht zu viel Speicher (wie jedes Zeichen auf True / False in einem Array Mapping). Dinge, die ich bisher ausprobiert habe:

  • regexp - nicht ganz performant
  • trimmen und prüfen, ob die Länge 0 ist - nicht ganz performant, verwendet auch zusätzlichen Speicher, um die abgeschnittene Zeichenfolge zu speichern
  • prüft jedes Zeichenkettenzeichen auf einen Hash-Satz mit Leerzeichen ( if (!whitespaceCharactersMap[str[index]]) ... ) - funktioniert gut genug
  • Meine aktuelle Lösung verwendet fest codierte Vergleiche:

    %Vor%

Dies scheint 50-100% schneller zu funktionieren als Hash-Einstellungen (getestet in Chrome).

Sieht oder kennt jemand weitere Möglichkeiten?

Update 1

Ich werde einige der Kommentare hier beantworten:

  • Es wird nicht nur die Benutzereingabe auf Leerheit überprüft. Ich muss bestimmte Datenformate analysieren, bei denen Leerzeichen getrennt behandelt werden müssen.
  • Es ist eine Optimierung wert. Ich habe den Code zuvor profiliert. Die Überprüfung auf leere Zeichenfolgen scheint ein Problem zu sein. Und wie wir gesehen haben, kann der Leistungsunterschied zwischen den Ansätzen bis zu 10 mal betragen, es lohnt sich auf jeden Fall.
  • Im Allgemeinen finde ich diese Herausforderung "Hash-Set vs. Regex vs. Switch vs. Branching" sehr erzieherisch.
  • Ich brauche die gleiche Funktionalität für Browser wie auch für node.js.

Hier sind meine Leistungstests:

Ссылка

Ich wäre Ihnen dankbar, wenn Sie diese Tests ein paar Mal durchführen würden.

Vorläufige Schlussfolgerungen:

  • branchlessTest ( a^9*a^10*a^11... ) ist extrem schnell in Chrome und Firefox, aber nicht in Safari. Wahrscheinlich die beste Wahl für Node.js aus der Performance-Perspektive.
  • switchTest ist auch ziemlich schnell auf Chrom und Firefox, aber überraschenderweise das langsamste in Safari und Opera
  • Regexps mit re.test (str) funktionieren überall gut, sogar am schnellsten in Opera.
  • Hash und Branching zeigen fast überall fast identische Ergebnisse. Vergleich ist auch ähnlich, oft schlechteste Leistung (dies kann aufgrund der Implementierung sein, sollte die Überprüfung für ' ' der erste sein).

Um es zusammenzufassen, für meinen Fall werde ich mich für die folgende regexp-Version entscheiden:

%Vor%

Gründe:

  • Branchless-Version ist cool in Chrome und Firefox, aber ist nicht ganz tragbar
  • switch ist in Safari zu langsam
  • Regexps scheinen überall gut zu funktionieren, sie werden auch im Code sehr kompakt sein
lexicore 09.06.2013, 13:30
quelle

3 Antworten

7

Eine hartcodierte Lösung scheint die beste zu sein, aber ich denke, switch sollte schneller sein. Es hängt davon ab, wie JavaScript-Interpreter diese behandelt (die meisten Compiler machen dies sehr effizient), daher ist browserspezifisch (d. H. Schnell in einigen, langsam in anderen). Außerdem bin ich mir nicht sicher, wie schnell JavaScript mit UTF-Strings ist, also könnten Sie versuchen, ein Zeichen in seinen ganzzahligen Code zu konvertieren, bevor Sie die Werte vergleichen.

%Vor%

Eine andere Sache, die Sie beachten sollten, ist for zu ändern:

%Vor%

Bearbeiten

Ihr jsPerf-Test hat einige Änderungen erhalten, die aktuelle hier . Mein Code ist in Chrome 26 und 27 und in IE10 deutlich schneller, aber in Firefox 18 auch der langsamste.

Ich habe den gleichen Test (ich weiß nicht, wie man jsPerf diese speichern kann) auf Firefox 20.0 unter 64-bit Linux ausgeführt und es hat sich als einer der zwei schnellsten herausgestellt (gebunden mit trimTest , beide bei etwa 11,8 M ops / s). Ich habe auch Firefox 20.0.1 auf WinXP getestet, aber unter einer VirtualBox (immer noch unter 64bit Linux, was hier einen signifikanten Unterschied machen könnte), die 10% ops / sec zu switchTest mit% co_de gab % kommt mit 7.3M Ops / Sekunde an zweiter Stelle.

Also, ich vermute, dass die Leistung von der Browser-Version und / oder vielleicht sogar von dem zugrundeliegenden Betriebssystem / der Hardware abhängt (ich nehme an, der obige FF18-Test war auf Win). In jedem Fall müssen Sie, um eine wirklich optimale Version zu erstellen, viele Versionen erstellen, die jeweils auf allen Browsern, Betriebssystemen, Architekturen usw. getestet werden. Sie können sich darauf konzentrieren und dann auf Ihrer Seite die am besten geeignete Version hinzufügen für den Browser des Besuchers, Betriebssystem, Architektur, ... Ich bin mir nicht sicher, welche Art von Code die Mühe wert ist.

    
Vedran Šego 09.06.2013, 14:05
quelle
4

Da die Verzweigung viel teurer ist als die meisten anderen Operationen, möchten Sie die Verzweigungen auf ein Minimum reduzieren. Daher ist Ihre Sequenz von if / else-Anweisungen möglicherweise nicht sehr performant. Eine Methode, die stattdessen hauptsächlich Mathematik verwendet, wäre viel schneller. Zum Beispiel:

Eine Möglichkeit zur Durchführung einer Gleichheitsprüfung ohne Verwendung von Verzweigungen besteht in der Verwendung bitweiser Operationen. Ein Beispiel ist, zu überprüfen, dass a == b:

%Vor%

Da der xor zweier ähnlicher Bits (dh 1 ^ 1 oder 0 ^ 0) 0 ist, ergibt das Xoring von zwei gleichen Werten 0. Dies ist nützlich, weil es uns erlaubt, 0 als einen "wahren" Wert zu behandeln, und mache mehr Mathe. Stellen Sie sich vor, wir haben eine Reihe boolescher Variablen, die auf diese Weise dargestellt werden: Zahlen ungleich Null sind falsch, und null bedeutet "wahr". Wenn wir fragen wollen: "Ist das wahr?" wir multiplizieren sie einfach alle zusammen. Wenn einer von ihnen wahr wäre (gleich Null), wäre das gesamte Ergebnis Null.

So würde der Code beispielsweise so aussehen:

%Vor%

Der Hauptgrund, dass dies performanter wäre, als einfach etwas zu tun:

%Vor%

ist, dass JavaScript Boolesche Operatoren kurzschließt, was bedeutet, dass jedes Mal, wenn der Operator || verwendet wird, nicht nur die Operation oder ausführt, sondern auch prüft, ob es beweisen kann, dass die Anweisung bisher wahr sein muss Dies ist eine Verzweigungsoperation, die teuer ist. Der mathematische Ansatz hingegen beinhaltet keine Verzweigung außer der if-Anweisung selbst und sollte daher viel schneller sein.

    
joshlf 09.06.2013 14:16
quelle
0

Dies erstellt und verwendet eine 'Hash' Suche nach den Zeichen der Zeichenkette, wenn es einen Nicht-Whitespace erkennt und dann false zurückgibt:

%Vor%

Ich bin mir nicht sicher über die Leistung (noch) . Nach einem kurzen Test auf Jsperf, es erweist sich als ziemlich langsam im Vergleich zu RegExp mit /^\s*$/ .

bearbeiten:

Es sieht so aus, als ob die Lösung, mit der Sie arbeiten sollten, wahrscheinlich von der Art der Daten abhängt, mit denen Sie arbeiten: Sind die Daten meistens Whitespace oder meistens kein Whitespace? Auch meistens ASCII Text? Sie können es möglicherweise für durchschnittliche Testfälle beschleunigen, indem Sie Bereichsüberprüfungen (über if ) für allgemeine Zeichenbereiche ohne Leerzeichen verwenden, switch für die häufigsten Leerzeichen verwenden und dann einen Hash-Lookup für alles andere verwenden. Dies wird wahrscheinlich die durchschnittliche Leistung der Tests verbessern, wenn die meisten der zu testenden Daten aus den gebräuchlichsten Zeichen bestehen (zwischen 0x0 und 0x7F).

Vielleicht könnte so etwas (ein Hybrid aus if / switch / hash) funktionieren:

%Vor%     
jongo45 15.06.2013 19:43
quelle

Tags und Links