2009-08-17 24 views
9

Um Platz zu sparen und die Komplexität der Datenkonsistenz zwischen verschiedenen Quellen zu erhalten, überlege ich, Start/Ende-Indizes für einige Teilstrings zu speichern, anstatt die Teilstrings selbst zu speichern. Der Trick ist, wenn ich das mache, ist es möglich, dass ich die ganze Zeit Slices kreiere. Ist das etwas zu vermeiden? Ist der Slice-Operator schnell genug, muss ich mir keine Sorgen machen? Wie wäre es mit dem neuen Objekterzeugungs-/Zerstörungsaufwand?Wie schnell ist Pythons Slice


Okay, ich habe meine Lektion gelernt. Optimieren Sie nicht, es sei denn, es gibt ein echtes Problem, das Sie beheben möchten. (Natürlich bedeutet das nicht, unnötig unnötigen Code zu korrigieren, aber das ist nebensächlich ...) Auch testen und profilieren bevor es zum Stack-Overflow kommt. = D Danke an alle!

+8

Warum nicht einfach ausprobieren? Schreibe einen einfachen Test. –

+0

stimme ich zu und wählte balpha, aber ich fragte mich immer, wie schnell das Python-Stück war. Ich benutze es die ganze Zeit so einfach wie eine einfache Zuweisung, aber ich bin mir sicher, dass es ziemlich viel langsamer ist. –

+0

-1: habe kein Timing-Experiment durchgeführt. –

Antwort

8
  1. Schnell genug im Gegensatz zu was? Wie machst du es gerade jetzt? Was genau speicherst du, was genau suchst du? Die Antwort hängt wahrscheinlich sehr davon ab. Was bringt uns zu ...

  2. Messen! Diskutiere und analysiere nicht theoretisch. versuchen Sie und messen Sie, was der performantere Weg ist. Dann entscheiden Sie, ob der mögliche Leistungszuwachs die Refactoring Ihrer Datenbank rechtfertigt.

Edit: Ich lief ein Test-String im Vergleich zu Nachschlag in einer auf (start, end) Tupeln verkeilt dict Schneiden zu messen. Es deutet darauf hin, dass es keinen großen Unterschied gibt. Es ist jedoch ein ziemlich naive Test, also nehmen Sie es mit einer Prise Salz.

+1

Die aktuelle Methode speichert nur einen Text, Sätze und Token im Satz als separate Strings (in der Datenbank) und verbindet sie miteinander. Es scheint mir eine Menge unnötiger Blähungen zu sein. Ein 2-MB-Text endet mit einer Datenbank von 28 MB. Wie auch immer, was immer abgerufen wird, sind einzelne Sätze aus dem Text. Die Alternative besteht darin, den Text basierend auf den gespeicherten Indizes zu schneiden. Aber Sie haben einen wirklich guten Punkt. Messen ist wahrscheinlich der beste Weg zu gehen. = P – tehgeekmeister

+1

Unterschätzen Sie auch nicht den Entscheidungsteil: Wenn es einen Performance-/Speicherplatz-Kompromiss gibt (und die meiste Zeit, die es gibt), müssen Sie berücksichtigen, welche Ressourcen Sie haben. 28mb ist nicht viel, wenn Sie wirklich die CPU-Zeit benötigen, aber eine Terabyte-Festplatte zu Ihrer Verfügung haben. 28 MB * ist * viel, wenn Sie ein kleines Embedded-System betreiben, auf das nur einmal am Tag zugegriffen wird.Nun, ich schätze, das Ganze, was ich gerade geschrieben habe, läuft auf "Es kommt immer drauf an" :-) – balpha

+0

@tehgeekmeister: Bitte aktualisieren Sie Ihre Frage mit diesen zusätzlichen Fakten. –

-1

vorzeitige Optimierung ist der Dreh- und Angelpunkt aller Übel.

Beweisen Sie selbst, dass Sie Code wirklich optimieren müssen, dann handeln Sie.

1

Ich habe keine Messungen entweder getan, aber da es klingt wie Sie sind bereits einen C-Ansatz für ein Problem in Python nehmen, könnten Sie einen Blick auf Python's built-in mmap library nehmen wollen:

Memory- Zugewiesene Dateiobjekte verhalten sich wie Strings und ähnliche Dateiobjekte. Im Gegensatz zu normalen String-Objekten sind diese jedoch veränderbar. An den meisten Stellen, an denen Strings erwartet werden, können Sie mmap-Objekte verwenden. Zum Beispiel können Sie das re-Modul verwenden, um eine Memory-Mapped-Datei zu durchsuchen. Da sie veränderbar sind, können Sie ein einzelnes Zeichen ändern, indem Sie obj [index] = 'a' ausführen, oder eine Teilzeichenfolge ändern, indem Sie eine Teilmenge zuweisen: obj [i1: i2] = '...'. Sie können auch Daten lesen und schreiben, die an der aktuellen Dateiposition beginnen, und die Datei an verschiedenen Positionen suchen().

Ich bin nicht sicher von Ihrer Frage, ob das genau das ist, wonach Sie suchen. Und es wiederholt sich, dass Sie einige Messungen vornehmen müssen. Python's timeit library ist die einfache zu verwenden, aber es gibt auch cProfile oder hotshot, obwohl ist Gefahr, aus der Standard-Bibliothek, wie ich es verstehe, entfernt werden.

3

In einem Kommentar erwähnt das OP Bloat "in der Datenbank" - aber keine Informationen darüber, über welche Datenbank er spricht; Aus den wenigen Informationen in diesem Kommentar scheint es, dass Python-String-Slices nicht unbedingt das sind, was involviert ist, sondern das "Slicen" würde von der DB-Engine beim Abrufen ausgeführt werden.

Wenn das die tatsächliche Situation ist dann würde ich auf allgemeine Prinzipien gegen das Speichern von redundanten Informationen in der DB empfehlen - eine "normale Form" (vielleicht in einem laxen Sinn des Ausdrucks ;-) wobei Informationen nur einmal gespeichert und abgeleitet werden Informationen werden neu berechnet (oder Cache-Ladung der DB-Engine, etc ;-) sollte die Norm sein, und "Denormalisierung" durch absichtliche Speicherung abgeleiteter Informationen sehr stark die Ausnahme und nur, wenn durch spezifische, gut bemessene Retrieval-Performance-Anforderungen gerechtfertigt.

Wenn der Verweis auf "Datenbank" eine Fehlleitung war ;-), oder eher in einem laxen Sinn wie ich für "normale Form" oben verwendet habe; dann kann eine andere Überlegung gelten: Da Python-Strings unveränderlich sind, Es scheint natürlich zu sein, dass man keine Schnitte durch Kopieren machen muss, sondern dass jede Scheibe einen Teil des Speicherplatzes des Elternteils, von dem sie geschnitten wird, wiederverwenden kann (ähnlich wie es bei scheibenförmigen Arrays der Fall ist). Dies ist jedoch nicht Teil des Python-Kerns. Ich habe einmal einen Patch für diesen Zweck versucht, aber das Problem, einen Verweis auf den großen String hinzuzufügen und ihn so im Speicher zu halten, nur weil ein winziger Teilstring davon immer noch referenziert wird, war für die allgemeine Anpassung groß. Dennoch wäre es möglich, eine spezielle Unterklasse von Zeichenfolgen (und eine von Unicode) für den Fall zu erstellen, in dem die große "Eltern" Zeichenfolge sowieso im Speicher bleiben muss. Derzeit buffer macht ein kleines bisschen davon, aber Sie können String-Methoden für ein Pufferobjekt nicht aufrufen (ohne explizit zu einem String-Objekt zuerst zu kopieren), so dass es nur für die Ausgabe und ein paar spezielle Fälle wirklich nützlich ist ... aber da ist kein wirklicher konzeptioneller Block gegen das Hinzufügen einer String-Methode (ich bezweifle, dass das im Core übernommen würde, aber es sollte trotzdem recht einfach als Drittanbieter-Modul zu pflegen sein ;-).

Der Wert eines solchen Ansatzes kann schwerlich durch Messung auf die eine oder andere Art und Weise bewiesen werden - die Geschwindigkeit wäre dem derzeitigen implizit kopierenden Ansatz sehr ähnlich; Der Vorteil wäre, den Speicherbedarf zu reduzieren, der zwar keinen Python-Code schneller machen würde, aber ein bestimmtes Programm auf einem Rechner mit etwas weniger RAM oder besser Multi-Task bei mehreren Instanzen ausführen könnte werden gleichzeitig in getrennten Prozessen verwendet. Ein ähnlicher, aber reichhaltigerer Ansatz wurde einmal im Kontext von C++ mit rope durchgespielt (aber beachten Sie, dass es nicht zum Standard wurde ;-).

1

Wären Slices unwirksam, weil sie Kopien der Quellzeichenfolge erstellen? Dies kann oder kann kein Problem sein. Wenn es sich als ein Problem herausstellt, wäre es nicht möglich, einfach eine "String-Ansicht" zu implementieren; ein Objekt, das einen Verweis auf die Quellzeichenfolge hat und einen Start- und Endpunkt hat. Bei Zugriff/Wiederholung liest es nur aus der Quellzeichenfolge.

+0

Das war meine Sorge. Aber ich denke, jeder hatte Recht: Ich muss noch nicht optimieren, und wenn ich es getan hätte, hätte ich messen und testen sollen, bevor ich hierher kam. – tehgeekmeister