Raku: Gibt es eine SUPER schnelle Möglichkeit, ein Array in einen String umzuwandeln, ohne dass die Leerzeichen die Elemente trennen?

8

Ich muss Tausende von binären Byte-Strings, die jeweils etwa ein Megabyte lang sind, in ASC-Strings konvertieren. Dies ist, was ich getan habe und scheint zu langsam:

sub fileToCorrectUTF8Str ($fileName) { # binary file
    my $finalString = "";
    my $fileBuf = slurp($fileName, :bin);    
    for @$fileBuf { $finalString = $finalString ~ $_.chr; };    
    return $finalString;
}

~ @ b verwandelt @b in einen String, bei dem alle Elemente durch Leerzeichen getrennt sind, aber das ist nicht das, was ich will. Wenn @b = <abcd>; das ~ @ b ist "abc d"; aber ich will nur "abcd" und ich will das WIRKLICH schnell machen.

Also, was ist der beste Weg? Ich kann Hyper nicht wirklich für Parallelität verwenden, da die endgültige Zeichenfolge sequentiell aufgebaut ist. Oder kann ich?

lisprogtor
quelle

Antworten:

10

TL; DR Auf einem alten Rakudo .decodeist etwa 100-mal so schnell.

In längerer Form passend zu Ihrem Code:

sub fileToCorrectUTF8Str ($fileName) { # binary file
  slurp($fileName, :bin).decode
}

Leistungshinweise

Zuerst habe ich Folgendes zum Testen geschrieben:

# Create million and 1 bytes long file:
spurt 'foo', "1234\n6789\n" x 1e5 ~ 'Z', :bin;

# (`say` the last character to check work is done)
say .decode.substr(1e6) with slurp 'foo', :bin;

# fileToCorrectUTF8Str 'foo' );

say now - INIT now;

Auf dem Rakudo von 2018.12TIO.run .decodewiegt das oben Genannte ungefähr .05Sekunden pro Million Byte Datei anstelle von ungefähr 5Sekunden für Ihre Lösung.

Sie könnten / sollten natürlich auf Ihrem System testen und / oder spätere Versionen von Rakudo verwenden. Ich würde erwarten, dass der Unterschied in der gleichen Reihenfolge bleibt, aber dass sich die absoluten Zeiten im Laufe der Jahre deutlich verbessern. [1]

Warum ist es 100x so schnell?

Nun, zunächst einmal , @auf einem Buf/ Blobexplizit Raku Kräfte , die das ehemals sehen einzelne Element ( ein Puffer) als Plural Sache (eine Liste von Elementen aka mehrere Artikel s ). Dies bedeutet eine Iteration auf hoher Ebene, die für eine Million Elementpuffer sofort eine Million Iterationen / Operationen auf hoher Ebene statt nur einer ist Operation auf hoher Ebene ist.

Zweitens .decodevermeidet die Verwendung nicht nur die Iteration, sondern verursacht nur einmal pro Datei einen relativ langsamen Overhead für Methodenaufrufe, während bei der Iteration möglicherweise eine Million .chrAufrufe pro Datei auftreten. Methodenaufrufe sind (zumindest semantisch) spät gebunden, was im Prinzip relativ kostspielig ist, beispielsweise wenn ein Sub anstelle einer Methode aufgerufen wird (Subs sind im Allgemeinen früh gebunden ).

Das alles sagte:

  • Denken Sie daran, dass der Vorbehalt leer ist [1] . Beispielsweise generieren die Standardklassen von rakudo Methodencaches, und es ist plausibel, dass der Compiler die Methode ohnehin nur einbindet, sodass der Aufwand für den Aspekt des Methodenaufrufs möglicherweise vernachlässigbar ist.

  • Siehe auch die Seite Leistung des Dokuments , insbesondere Vorhandenen Hochleistungscode verwenden .

Ist die Buf.StrFehlermeldung LTA ?

Update Siehe den Kommentar von Liz ++.

Wenn Sie versuchen, .Strein Bufoder Blob(oder ein gleichwertiges Element, z. B. das ~Präfix) zu verwenden, wird eine Ausnahme angezeigt. Derzeit lautet die Nachricht:

Cannot use a Buf as a string, but you called the Str method on it

Das Dokument für .Strein Buf/Blob sagt derzeit:

Um in eine Str zu konvertieren, müssen Sie verwenden .decode.

Es ist wohl LTA, dass die Fehlermeldung nicht dasselbe andeutet.

Dann wieder, bevor sie entscheidet , was ist, dies zu tun, wenn überhaupt, müssen wir was zu beachten ist und wie Folk könnte von etwas lernen, was schief geht, einschließlich Signale darüber, wie Fehlermeldungen, und auch , was und wie sie tun in Tatsache lernen derzeit und voreingenommen unsere Reaktionen auf den Aufbau der richtigen Kultur und Infrastruktur.

Insbesondere wenn die Leute leicht eine Verbindung zwischen einer Fehlermeldung, die sie sehen, und einer Online-Diskussion, die darauf eingeht, herstellen können, muss dies berücksichtigt und möglicherweise gefördert und / oder erleichtert werden.

Zum Beispiel gibt es jetzt diese SO, die dieses Problem mit der darin enthaltenen Fehlermeldung abdeckt, sodass Google wahrscheinlich jemanden hierher bringt. Sich darauf zu stützen, könnte ein geeigneterer Weg sein, als die Fehlermeldung zu ändern. Oder vielleicht auch nicht. Die Änderung wäre einfach ...

Bitte erwägen Sie, unten einen Kommentar abzugeben und / oder vorhandene Rakudo-Probleme zu durchsuchen, um festzustellen , ob eine Verbesserung der Buf.StrFehlermeldung in Betracht gezogen wird und / oder ob Sie ein Problem öffnen möchten, um eine Änderung vorzuschlagen. Jeder bewegte Stein ist zumindest eine großartige Übung und verbessert (unsere Sicht auf) den Berg , wenn unsere gemeinsamen Anstrengungen immer klüger werden .

Fußnoten

[1] Wie das bekannte lateinische Sprichwort Caveat Empty sagt , kann sowohl die absolute als auch die relative Leistung eines bestimmten Raku-Features und allgemein eines bestimmten Codes aufgrund von Faktoren wie den Fähigkeiten des eigenen Systems und seiner Auslastung während der Zeit immer variieren Ausführen des Codes und alle vom Compiler vorgenommenen Optimierungen. Wenn Ihr System beispielsweise "leer" ist, wird Ihr Code möglicherweise schneller ausgeführt. Wenn Sie ein oder drei Jahre warten, bis der Compiler schneller wird, sehen die Fortschritte bei der Leistung von Rakudo weiterhin vielversprechend aus .

Raiph
quelle
2
Es gibt verschiedene Möglichkeiten, dies weiter zu optimieren. slurpist IO::Path.slurpin diesem Fall nur ein Wrapper. Wenn Sie .IO.slurpstattdessen anrufen, wird dies in meinen Benchmarks um etwa 2% schneller. Wenn Sie die Datei mit schlürfen :enc<latin1>, erhalten Sie einen Zeichenpuffer wie bei der Standard-UTF-8-Codierung. Überspringen Sie jedoch die Überprüfung, ob die verschluckte Datei tatsächlich gültiges UTF-8 ist, das Sie beim Decodieren ausführen auf jeden Fall zu einem UTF-8-String, was dies ebenfalls um etwa 10% schneller macht.
Kaiepi
Vielen Dank für Ihre Hilfe !!! Mit .decode und anderen geringfügigen Codeänderungen rasiere ich ungefähr 8 Sekunden für jede lange Zeichenfolge, die ich verarbeiten muss. Vielen Dank !!!
Lisprogtor
Hi @lisprogtor Die Metapher "rasieren" bedeutet "eine Zahl um einen sehr kleinen Betrag reduzieren" . Was war Ihre Zeit, bevor Sie es auf ungefähr 8 Sekunden pro langer Saite reduziert haben? Ist die Reduzierung ausreichend?
Raiph
8 Sek. Ist definitiv besser als "Rasieren"! Vielen Dank !!!
Lisprogtor