6 Stimmen

Generatorfunktion Leistung

Ich versuche, die Leistung einer Generatorfunktion zu verstehen. Ich habe cProfile und das Modul pstats verwendet, um Profildaten zu sammeln und zu untersuchen. Die betreffende Funktion ist die folgende:

def __iter__(self):
    delimiter  = None
    inData     = self.inData
    lenData    = len(inData)
    cursor     = 0
    while cursor < lenData:
        if delimiter:
            mo = self.stringEnd[delimiter].search(inData[cursor:])
        else:
            mo = self.patt.match(inData[cursor:])
        if mo:
            mo_lastgroup = mo.lastgroup
            mstart       = cursor
            mend         = mo.end()
            cursor       += mend
            delimiter = (yield (mo_lastgroup, mo.group(mo_lastgroup), mstart, mend))
        else:
            raise SyntaxError("Unable to tokenize text starting with: \"%s\"" % inData[cursor:cursor+200])

self.inData ist eine Unicode-Textzeichenfolge, self.stringEnd ist ein Diktat mit 4 einfachen Regexen, self.patt ist ein großer Regex. Das Ganze dient dazu, die große Zeichenkette in kleinere Zeichenketten aufzuteilen, eine nach der anderen.

Beim Profiling eines Programms, das diese Funktion verwendet, habe ich festgestellt, dass der größte Teil der Programmlaufzeit in dieser Funktion verbracht wird:

In [800]: st.print_stats("Scanner.py:124")

         463263 function calls (448688 primitive calls) in 13.091 CPU seconds

   Ordered by: cumulative time
   List reduced from 231 to 1 due to restriction <'Scanner.py:124'>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    10835   11.465    0.001   11.534    0.001 Scanner.py:124(__iter__)

Betrachtet man jedoch das Profil der Funktion selbst, so wird nicht viel Zeit mit den Unteraufrufen der Funktionen verbracht:

In [799]: st.print_callees("Scanner.py:124")
   Ordered by: cumulative time
   List reduced from 231 to 1 due to restriction <'Scanner.py:124'>

Function                  called...
                              ncalls  tottime  cumtime
Scanner.py:124(__iter__)  ->   10834    0.006    0.006  {built-in method end}
                               10834    0.009    0.009  {built-in method group}
                                8028    0.030    0.030  {built-in method match}
                                2806    0.025    0.025  {built-in method search}
                                   1    0.000    0.000  {len}

Der Rest der Funktion ist nicht viel mehr als while, Zuweisungen und if-else. Auch die send Methode des Generators, die ich verwende, ist schnell:

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
13643/10835    0.007    0.000   11.552    0.001 {method 'send' of 'generator' objects}

Ist es möglich, dass die yield Der größte Teil der Zeit wird darauf verwendet, einen Wert an den Verbraucher zurückzugeben?! Gibt es sonst noch etwas, das mir nicht bekannt ist?

EDITAR :

Ich hätte vielleicht erwähnen sollen, dass die Generatorfunktion __iter__ ist eine Methode einer kleinen Klasse, also self verweist auf eine Instanz dieser Klasse.

2voto

ThomasH Punkte 20646

Dies ist eigentlich die Antwort von Dünen der sie leider nur als Kommentar abgab und nicht geneigt zu sein scheint, sie in eine richtige Antwort aufzunehmen.

Der Hauptschuldige an der Leistung waren die String Slices. Einige Timing-Messungen haben gezeigt, dass die Slicing-Leistung bei großen Slices (d.h. wenn man ein großes Slice aus einer bereits großen Zeichenkette nimmt) spürbar abnimmt. Um das zu umgehen, verwende ich jetzt die pos Parameter für die Methoden des Regex-Objekts:

    if delimiter:
        mo = self.stringEnd[delimiter].search(inData, pos=cursor)
    else:
        mo = self.patt.match(inData, pos=cursor)

Dank an tous die geholfen haben.

1voto

Nick ODell Punkte 9096

Wenn ich Ihr Beispiel richtig lese, nehmen Sie ein Generatorobjekt, setzen es in delimiter und für ein Array-Lookup zu verwenden. Das ist vielleicht nicht Ihr Geschwindigkeitsproblem, aber ich bin ziemlich sicher, dass das ein Fehler ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X