2009-02-28 6 views
1

Ich versuche, die Amazon S3 python library zu manipulieren, um Chunked Handling von großen Dateien zu ermöglichen. Im Moment macht es einen "self.body = http_response.read()", wenn Sie also eine 3G-Datei haben, werden Sie das gesamte Ding in den Speicher einlesen, bevor Sie die Kontrolle darüber haben.Python: effizient Teile von Bytes in einen großen Brocken?

Mein aktueller Ansatz besteht darin, zu versuchen, die Schnittstelle für die Bibliothek gleich zu halten, aber einen Rückruf nach dem Lesen jedes einzelnen Datenblocks bereitzustellen. Etwas wie folgt aus:

data = [] 
while True: 
    chunk = http_response.read(CHUNKSIZE) 
    if not chunk: 
     break 
    if callback: 
     callback(chunk) 
    data.append(chunk) 

Jetzt brauche ich etwas zu tun:

self.body = ''.join(data) 

Ist beitreten die richtige Weg, dies zu tun oder gibt es eine andere (bessere) Möglichkeit, alle Stücke des Setzens zusammen?

Antwort

2

hm - welches Problem versuchen Sie zu lösen? Ich vermute, die Antwort hängt davon ab, was Sie mit den Daten zu tun versuchen.

Da im Allgemeinen Sie nicht eine ganze 3Gb-Datei im Speicher möchten, würde ich nicht die Stücke in einem Array speichern, sondern über die http_response iterieren und schreiben Sie es direkt auf Festplatte, in einer temporären oder persistenten Datei mit der normale write() -Methode für ein passendes Dateihandle.

Wenn Sie zwei Kopien der Daten im Speicher haben möchten, muss Ihre Methode mindestens 6 GB für Ihre hypothetische 3Gb-Datei sein, was vermutlich für die meisten Hardware von Bedeutung ist. Ich weiß, dass Array-Join-Methoden schnell sind und all das, aber da dies ein wirklich rambeschränkter Prozess ist, möchten Sie vielleicht einen Weg finden, es besser zu machen? StringIO (http://docs.python.org/library/stringio.html) erstellt Zeichenfolgenobjekte, an die im Speicher angehängt werden kann. der reine python-one, da er mit unveränderlichen Strings arbeiten muss, verwendet nur den Array-Join-Trick intern, aber der c-basierte cStringIO könnte tatsächlich an einen internen Speicherpuffer angehängt werden. Ich habe seinen Quellcode nicht zur Hand.

Wenn Sie eine Analyse der Daten durchführen und wirklich mit minimalem Aufwand im Speicher bleiben möchten, sollten Sie einige der Byte-Array-Objekte aus Numeric/NumPy als Alternative zu StringIO betrachten. Es handelt sich um Hochleistungscode, der für große Arrays optimiert ist und möglicherweise das ist, was Sie benötigen.

als nützliches Beispiel für eine Datei-Handling-Objekt für allgemeine Zwecke, die speichereffiziente Iterator freundlichen Ansatz hat man die django Datei obeject chunk Code verarbeitet möchten vielleicht überprüfen: http://code.djangoproject.com/browser/django/trunk/django/core/files/base.py.

+0

Ausgezeichneter Punkt bezüglich der Notwendigkeit von 6 GB anstelle von 3 mit meiner obigen Methode. Ich möchte die Chunks verarbeiten und sie loswerden (schreibe sie einfach in diesem Fall auf die Festplatte), aber ich wollte auch die existierende Semantik beibehalten, die Zugriff auf die Daten im Speicher bietet. Ich muss vielleicht auf Letzteres verzichten. – Parand

0

In Python3, bytes Objekte unterscheiden sich von str, aber ich weiß keinen Grund, warum es etwas falsch daran wäre.

0

join scheint in Ordnung, wenn Sie wirklich müssen die gesamte Zeichenfolge zusammen, aber dann wickeln Sie nur auf, speichert die ganze Sache in RAM sowieso. In einer Situation wie dieser würde ich versuchen, zu sehen, ob es einen Weg gibt, jeden Teil der Zeichenkette zu verarbeiten und dann den verarbeiteten Teil zu verwerfen, so dass Sie nur eine feste Anzahl von Bytes gleichzeitig im Speicher halten müssen. Das ist normalerweise der Punkt des Callback-Ansatzes. (Wenn Sie nur einen Teil eines Chunks gleichzeitig verarbeiten können, verwenden Sie einen Puffer als Warteschlange, um die unverarbeiteten Daten zu speichern.)

+0

Einverstanden, aber ich versuche, die vorhandene API zu bewahren, und das erfordert die ganze Sache im Speicher. Idealerweise wäre der Körper ein Generator, anstatt ein Stück Bytes zu sein, so dass der Benutzer damit umgehen kann, wie er will ... – Parand

3

'' join() ist die beste Methode, um Datenbrocken zusammenzuführen. Die Alternative läuft auf eine wiederholte Verkettung hinaus, die O (n ** 2) ist, aufgrund der Unveränderlichkeit von Strings und der Notwendigkeit, bei jeder Verkettung mehr zu erzeugen. Gegeben, diese wiederholte Verkettung wird durch neuere Versionen von CPython optimiert, wenn sie mit + = verwendet werden, um O (n) zu werden, aber diese Optimierung gibt ihr ohnehin nur eine grobe Entsprechung zu '' .join(), was explizit O (n) over ist die Anzahl der Bytes.

Verwandte Themen