Seite 1 von 1

Alternativen für String-Verknüpfung

Verfasst: Dienstag 29. September 2009, 11:58
von HWK
Da += für große Strings bekanntermaßen speicherhungrig und langsam sein kann, habe ich eine Alternative mit Liste und join ausprobiert. Von dem Ergebnis war ich dann aber enttäuscht.
Über Telnet werden mittels read_until (bildschirm)seitenweise die Ausgaben eines Servers für einen Ansi-Terminal gelesen, bis eine bestimmte Regex erfüllt ist. Dabei werden unterschiedlich große Blöcke von wenigen KB bis zu einem halben MB übertragen (entsprechend temp in read1). Diese Blöcke werden entweder mit += oder ''.join zusammengesetzt. Während eines Programmlaufs wird die Routine 21x aufgerufen und dabei insgesamt 12 MB Daten gelesen. Dies dauert mit beiden Varianten gut 8 Minuten ohne signifikanten Unterschied. Gibt es evtl. eine performantere Lösung oder sind bei diesen Datenmengen keine wesentlichen Unterschiede zu erwarten?

Code: Alles auswählen

def read1():
    output = []
    while True:
        temp = tn.read_until('ABC')
        output.append(temp)
        if 'DEF' in temp[-37:]:
            tn.write('\r\n')
            if REGEX.search(temp[-80:]):
                tn.write('GHI')
                break
    return ''.join(output).decode('cp850')

def read2():
    output = ''
    while True:
        output += tn.read_until('ABC')
        if 'DEF' in output[-37:]:
            tn.write('\r\n')
            if REGEX.search(output[-80:]):
                tn.write('GHI')
                break
    return output.decode('cp850')
MfG
HWK

Verfasst: Dienstag 29. September 2009, 12:50
von mkesper
Der begrenzende Faktor dürfte hier doch die Geschwindigkeit des Terminals sein. Meist ist 38400 chars / s eingestellt. In 8 Minuten wären das 18432000 Chars. man stty

Verfasst: Dienstag 29. September 2009, 15:40
von str1442
Stringaddition ist afaik in CPython effizient implementiert. In zb Java wird sie mittels einer immer neuen Erzeugung von StringBuilder Exemplaren implementiert; Das erzeugt dann wohl quadratische Laufzeit. Deshalb wird wohl angeraten, sich nicht auf CPython zu verlassen.

Verfasst: Dienstag 29. September 2009, 17:21
von HWK
mkallas hat geschrieben:Der begrenzende Faktor dürfte hier doch die Geschwindigkeit des Terminals sein. Meist ist 38400 chars / s eingestellt. In 8 Minuten wären das 18432000 Chars. man stty
Ich hätte wohl schreiben sollen: Terminal-Emulator. Über ein Netzwerk werden Daten gesendet, die ich auf dem PC über einen Emulator darstelle. Die Geschwindigkeit ist also sicher wesentlich höher, könnte aber trotzdem der begrenzende Faktor sein.
str1442 hat geschrieben:Stringaddition ist afaik in CPython effizient implementiert. In zb Java wird sie mittels einer immer neuen Erzeugung von StringBuilder Exemplaren implementiert; Das erzeugt dann wohl quadratische Laufzeit. Deshalb wird wohl angeraten, sich nicht auf CPython zu verlassen.
Kann ich daraus also schließen, dass ich unter CPython durchaus das meistens naheliegendere "+=" ohne Nachteil verwenden kann?
MfG
HWK

Verfasst: Dienstag 29. September 2009, 20:12
von DasIch
HWK hat geschrieben:Kann ich daraus also schließen, dass ich unter CPython durchaus das meistens naheliegendere "+=" ohne Nachteil verwenden kann?
Verwende einfach eine Liste und am Ende baust du den String mit "".join() zusammen.

Verfasst: Dienstag 29. September 2009, 21:55
von kbr
HWK hat geschrieben:Kann ich daraus also schließen, dass ich unter CPython durchaus das meistens naheliegendere "+=" ohne Nachteil verwenden kann?
MfG
HWK
Bei aktuellen Python-Versionen: ja. Früher war ".join" schneller. Das ist mittlerweile nicht mehr der Fall; probier es einfach mal aus.

Verfasst: Dienstag 29. September 2009, 23:29
von BlackJack
Wobei dass es *jetzt* nicht langsamer ist, nichts über die Zukunft aussagt. Das funktioniert im Moment, weil die Speicherverwaltung über Referenzzähler geschieht und man mit der Unveränderlichkeit von Zeichenketten "schummeln" kann -- wenn der Referenzzähler bei 1 steht, kann man Zeichenketten verändern, ohne dass es Seiteneffekte gibt. Die ganzen Referenzzähler sind aber mit ein Grund, warum man das GIL nicht entfernen kann, ohne Leistungseinbussen bei Single-Threaded-Programmen zu bekommen. Es kann also durchaus sein, dass der Trick bei dem ``+=`` auch irgendwann wieder aus CPython verschwindet.

Verfasst: Mittwoch 30. September 2009, 13:24
von HWK
DasIch hat geschrieben:Verwende einfach eine Liste und am Ende baust du den String mit "".join() zusammen.
Das ist ja meine Version 1.
kbr hat geschrieben:probier es einfach mal aus.
Das habe ich ja.
BlackJack hat geschrieben:Wobei dass es *jetzt* nicht langsamer ist, nichts über die Zukunft aussagt. Das funktioniert im Moment, weil die Speicherverwaltung über Referenzzähler geschieht und man mit der Unveränderlichkeit von Zeichenketten "schummeln" kann -- wenn der Referenzzähler bei 1 steht, kann man Zeichenketten verändern, ohne dass es Seiteneffekte gibt. Die ganzen Referenzzähler sind aber mit ein Grund, warum man das GIL nicht entfernen kann, ohne Leistungseinbussen bei Single-Threaded-Programmen zu bekommen. Es kann also durchaus sein, dass der Trick bei dem ``+=`` auch irgendwann wieder aus CPython verschwindet.
Genau das wollte ich wissen. Also doch lieber Liste und join.
MfG
HWK