Alternativen für String-Verknüpfung

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

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
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

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
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

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.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

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
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

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.
Benutzeravatar
kbr
User
Beiträge: 1508
Registriert: Mittwoch 15. Oktober 2008, 09:27

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.
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.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

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
Antworten