Schnell string zu integer Konvertierung in Python
Ein einfaches problem, wirklich: Sie haben eine Milliarde (1e+9) unsigned 32-bit-Ganzzahlen gespeichert, die als dezimale ASCII-strings in eine TSV (tab-separated values) - Datei. Konvertierung mithilfe int()
ist schrecklich langsam im Vergleich zu anderen Werkzeugen arbeiten auf dem gleichen Datenbestand. Warum? Und noch wichtiger: wie Sie es schneller zu machen?
Daher die Frage: was ist der Schnellste Weg möglich zu konvertieren eine Zeichenfolge in eine Ganzzahl in Python?
Was ich wirklich darüber nachdenken, einige semi-hidden Python-Funktionen, die sein könnte (ab)für diesen Zweck verwendet, nicht anders als Guido die Nutzung von array.array
in seinem "Optimierung Anekdote".
Sample-Daten (mit tabs erweitert werden, um Leerzeichen)
38262904 "pfv" 2002-11-15T00:37:20+00:00
12311231 "tnealzref" 2008-01-21T20:46:51+00:00
26783384 "hayb" 2004-02-14T20:43:45+00:00
812874 "qevzasdfvnp" 2005-01-11T00:29:46+00:00
22312733 "bdumtddyasb" 2009-01-17T20:41:04+00:00
Die Zeit, die es dauert das Lesen der Daten ist hier irrelevant, die Verarbeitung der Daten ist der Engpass.
Microbenchmarks
Alle der folgenden sind interpretierte Sprachen. Die host-Maschine läuft auf 64-bit-Linux.
Python 2.6.2 mit IPython 0.9.1, ~214k Wandlungen pro Sekunde (100%):
In [1]: strings = map(str, range(int(1e7)))
In [2]: %timeit map(int, strings);
10 loops, best of 3: 4.68 s per loop
REBOL-Version 3.0 2.100.76.4.2, ~231kcps (108%):
>> strings: array n: to-integer 1e7 repeat i n [poke strings i mold (i - 1)]
== "9999999"
>> delta-time [map str strings [to integer! str]]
== 0:00:04.328675
REBOL 2.7.6.4.2 (15-Mar-2008), ~523kcps (261%):
Als John bemerkt in den Kommentaren, diese version hat nicht erstellen Sie eine Liste von Ganzzahlen umgewandelt, so dass die Geschwindigkeit-Verhältnis gegeben ist, die relativ zu Python 4.99 s Laufzeit for str in strings: int(str)
.
>> delta-time: func [c /local t] [t: now/time/precise do c now/time/precise - t]
>> strings: array n: to-integer 1e7 repeat i n [poke strings i mold (i - 1)]
== "9999999"
>> delta-time [foreach str strings [to integer! str]]
== 0:00:01.913193
KDB+ 2,6 t 2009.04.15, ~2016kcps (944%):
q)strings:string til "i"$1e7
q)\t "I"$strings
496
- Versuchen
numpy.fromfile
laden 'eine Milliarde positiven ganzen zahlen" (btw, was meinst du mit 'Milliarden' (es ist10**9
in UNS, es könnte sein10**12
in Großbritannien)? - Guter Fang über die Milliarden, obwohl die letztere Verwendung kam aus der Mode in Großbritannien in den 1970er-Jahren.
- Haben Sie versucht, den code zu kompilieren ?
- (1) Bitte mehr explizit als "gespeichert als ASCII-Zeichenketten in einer text-Datei". Fixe Spalten oder getrennt? Ist das der einzige Typ der Daten in der Datei? Zeigen ein paar Beispiel-Zeilen. (2) Zeigen Sie uns den code, den SIE derzeit verwenden, wenn Sie uns glauben machen wollen, dass int() ist das problem und das ist keine Hausaufgaben-Frage (3) Bitte drücken Sie die Geschwindigkeit in SI-Einheiten eher als "schrecklich langsam". (4) Welche anderen tools? (5) Welche Plattform und welche version von Python?
- (6) Was ist die Durchschnittliche Anzahl der Ziffern in einen integer? (7) Sind die Ziffern dezimal/hex/oktal/etwas anderes?
- Vielen Dank für Ihre Kommentare, John. Ich integrierte Sie in die Frage.
- Die Python microbenchmark-code erstellt eine Liste von int-Ergebnisse und wirft die Liste Weg. Tun die REBOL-und KDB-codes bauen auch einen Behälter mit den Ergebnissen?
- KDB und die jüngsten REBOL 3-code tun, der REBOL-2-code nicht. Ich aktualisiert die Messungen, um dies zu reflektieren.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich könnte darauf hindeuten, dass für die raw-Geschwindigkeit, Python ist nicht das richtige Werkzeug für diese Aufgabe. Ein hand-codiert C-implementation schlagen Python leicht.
Erhalten Sie einen Prozentsatz der Geschwindigkeit, indem sichergestellt wird nur "local" - Variablen verwendet werden, die in Ihrem engsten Schleifen. Die
int
ist eine Funktion global, damit man ihn teurer sein als ein einheimischer.Brauchen Sie wirklich alle Milliarden zahlen im Speicher zu allen Zeiten. Erwägen Sie einige Iteratoren, um Ihnen nur ein paar Werte in einer Zeit, Milliarden von zahlen wird ein wenig Speicher. Das Anhängen an eine Liste, ein zu einer Zeit, ist zu verlangen, dass mehrere große Umschichtungen.
Erhalten Sie Ihren looping aus Python völlig, wenn möglich. Die map-Funktion, hier kann dein Freund sein. Ich bin mir nicht sicher, wie Ihre Daten gespeichert werden. Wenn es eine einzelne Zahl pro Zeile, die Sie reduzieren könnten, den code zu
Wenn es mehrere Werte pro Zeile sind Leerzeichen getrennt, das Graben in der itertools zu halten, die looping-code aus Python. Diese version hat den zusätzlichen Vorteil der Schaffung einer Anzahl iterator, so können Sie die Spule nur eine oder mehrere zahlen aus der Datei zu einem Zeitpunkt statt, eine Milliarde in einem Schuss.
Folgende meisten vereinfachten C-Erweiterung bereits verbessert stark auf die Gruppe vordefiniert, die Verwaltung zu konvertieren mehr als dreimal so viele strings pro Sekunde (650kcps vs 214kcps):
Diese offensichtlich nicht gerecht für Ganzzahlen beliebiger Länge und verschiedenen anderen besonderen Fällen, aber das ist kein problem in unserem Szenario.
strtoul()
?Stimme mit Greg; Python als interpretierte Sprache, ist in der Regel langsam. Sie könnten versuchen, den Quellcode kompilieren " on-the-fly mit der Psyco-Bibliothek oder die Kodierung der app in einem niedrigeren level-Sprache wie C/C++.
Als andere haben gesagt, Sie könnten code Ihre eigenen C-Modul zu tun, der mit der Analyse/Konvertierung für Sie. Dann könnte man einfach importieren und rufen Sie es auf. Sie könnten in der Lage sein zu verwenden, Pyrex oder seine Cython-Derivat zu generieren, die Ihr C aus Ihrem Python (durch hinzufügen von ein paar Typ einschränkende Hinweise auf die Python).
Lesen Sie mehr über Cython und sehen, ob das hilft.
Andere Frage in den Sinn kommt, aber ... was willst du tun mit diesen Milliarden Ganzzahlen? Ist es möglich, dass Sie vielleicht laden Sie Sie als Zeichenfolgen suchen, die für Sie als strings und führen ein faul Konvertierung notwendig? Oder könnte man parallelisieren, die Umwandlung und die andere Berechnungen mit
threading
odermultiprocessing
Module und Warteschlangen? (Ein oder mehrere threads/Prozesse, die die Durchführung der Umwandlung und Zuführung einer Warteschlange, aus der Sie Ihre Verarbeitungs-engine holt Sie). In anderen Worten würde eine producer/consumer-design das problem zu lindern?Kann es nicht eine option für Sie, aber ich würde mal wirklich hart auf über eine binäre Datei und nicht als text. Ändert es sich oft? Wenn nicht, können Sie pre-Prozess.
Dieses etwas, das numpy tut sehr gut:
np.fromstring(Zeile, dtype=np.float, sep=" ")