Ahoi. Ich wurde beauftragt, die Leistung von Bit.ly's Data_Hacks' sample.py als Übung zu verbessern.Iterieren über eine Datei ohne Linien auf der Grundlage der Bedingung effizient
Ich habe einen Teil des Codes zythonisiert. und enthielt einen PCG-Zufallsgenerator, der die Leistung bisher um etwa 20 Sekunden (im Vergleich zu 72s) verbessert und die Druckausgabe optimiert hat (durch Verwendung einer Basis-C-Funktion anstelle von Pythons write()
).
Das hat alles gut funktioniert, aber abgesehen von diesen Verbesserungen, würde ich gerne den Loop selbst optimieren.
Die Grundfunktion, wie in sample.py
der bit.ly gesehen:
def run(sample_rate):
input_stream = sys.stdin
for line in input_stream:
if random.randint(1,100) <= sample_rate:
sys.stdout.write(line)
Meine Implementierung:
cdef int take_sample(float sample_rate):
cdef unsigned int floor = 1
cdef unsigned int top = 100
if pcg32_random() % 100 <= sample_rate:
return 1
else:
return 0
def run(float sample_rate, file):
cdef char* line
with open(file, 'rb') as f:
for line in f:
if take_sample(sample_rate):
out(line)
Was ich jetzt verbessern möchte, speziell die nächste Zeile übersprungen wird (und vorzugsweise tun Sie dies wiederholt), wenn mein take_sample() nicht True
zurückgibt.
Meine aktuelle Implementierung ist dies:
def run(float sample_rate, file):
cdef char* line
with open(file, 'rb') as f:
for line in f:
out(line)
while not take_sample(sample_rate):
next(f)
, die nichts zu tun, scheinen die Leistung zu verbessern - was ich mich zu vermuten, habe lediglich einen continue
Ruf nach einer, wenn der Bedingung an der Spitze der Schleife ersetzt, mit meine next(f)
. diese
Die Frage ist also:
Gibt es eine effizientere Art und Weise in einer Schleife über eine Datei (in Cython)?
Ich möchte Linien ganz wegzulassen, nur dann wirklich, wenn ich mein nennen out()
zugegriffen werden sollte sie bedeutet - ist dies bereits der Fall in for
Schleife des Python? Ist line
ein Zeiger (oder vergleichbar mit) auf die Zeile der Datei? Oder lädt die Schleife das tatsächlich?
Ich weiß, dass ich es verbessern könnte, indem ich es komplett in C schreibe, aber ich würde gerne wissen, wie weit ich es schaffen kann, mit python/cython weiterzumachen.
Update: Ich habe eine C-Variante meines Codes - mit dem gleichen Testfall - getestet und es bei unter 2s (überraschend niemand). Obwohl es richtig ist, dass der Zufallsgenerator und die Datei-E/A im Allgemeinen zwei große Flaschenhälse sind, sollte darauf hingewiesen werden, dass die Dateiverarbeitung von python an sich schon langsam ist.
Also, gibt es eine Möglichkeit, die Datei lesen von C zu verwenden, außer die Schleife selbst in Cython implementieren? Der Overhead verlangsamt den Python-Code immer noch deutlich, was mich dazu bringt, mich zu fragen, ob ich einfach an der Schallmauer der Performance stehe, wenn es um die Dateiverwaltung mit Cython geht?
Diese Beschreibung könnte helfen: http://rabexc.org/posts/io-performance-in-python –
Engpässe sind Datei-IO und die Zufallsfunktion. Das ursprüngliche Skript hat also kein wesentliches Optimierungspotenzial. – Daniel
Jede Iteration auf 'f' liest eine Zeile. Eine Zeile ist definiert als die Zeichenfolge von Bytes bis zum nächsten '\ nl'. Die einzige Möglichkeit, die der Leser findet, ist das Lesen der Bytes nacheinander. Für einen Text gibt es keinen Index für Zeilenanfänge, den er zum "Suchen" verwenden kann. Es kann also nicht zur nächsten Zeile springen, ohne den aktuellen zu lesen. – hpaulj