Python: эффективно объединить куски байтов в один большой кусок? - PullRequest
1 голос
/ 28 февраля 2009

Я пытаюсь настроить библиотеку Amazon S3 python , чтобы разрешить обработку больших файлов по частям. Прямо сейчас он выполняет функцию «self.body = http_response.read ()», поэтому, если у вас есть файл 3G, вы собираетесь прочитать все это в память, прежде чем получить какой-либо контроль над ним.

Мой текущий подход состоит в том, чтобы попытаться сохранить интерфейс библиотеки таким же, но обеспечить обратный вызов после чтения каждого куска данных. Примерно так:

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

Теперь мне нужно сделать что-то вроде:

self.body = ''.join(data)

Является ли join правильным способом сделать это или есть другой (лучший) способ собрать все куски вместе?

Ответы [ 4 ]

3 голосов
/ 28 февраля 2009

'' join () - лучший способ объединения кусков данных. Альтернатива сводится к повторной конкатенации, которая составляет O (n ** 2) из-за неизменности строк и необходимости создавать больше при каждой конкатенации. Учитывая, что эта повторяющаяся конкатенация оптимизирована последними версиями CPython, если она используется с + =, чтобы стать O (n), но эта оптимизация в любом случае дает ему только грубый эквивалент. количество байтов.

2 голосов
/ 28 февраля 2009

хм - какую проблему вы пытаетесь решить? Я подозреваю, что ответ зависит от того, что вы пытаетесь сделать с данными.

Поскольку в общем случае вам не нужен целый 3Gb-файл в памяти, я не буду хранить фрагменты в массиве, а перебирать http_response и записывать его прямо на диск, во временный или постоянный файл с использованием обычного Метод write () для соответствующего дескриптора файла.

если вы хотите получить две копии данных в памяти, для вашего метода потребуется не менее 6 ГБ для вашего гипотетического файла 3 ГБ, что, вероятно, важно для большинства аппаратных средств. Я знаю, что методы соединения с массивами бывают быстрыми и все такое, но, поскольку это действительно ограниченный процесс, возможно, вы хотите найти способ сделать это лучше? StringIO (http://docs.python.org/library/stringio.html) создает строковые объекты, которые могут быть добавлены в память; чисто Python, поскольку он должен работать с неизменяемыми строками, просто использует трюк соединения с массивом внутри, но cStringIO на основе c может фактически добавить к внутреннему буферу памяти. У меня нет его исходного кода под рукой, так что это будет нести проверку.

если вы хотите провести какой-то анализ данных и действительно хотите сохранить в памяти минимальные издержки, вы можете рассмотреть некоторые объекты байтового массива из Numeric / NumPy в качестве альтернативы StringIO. они представляют собой высокопроизводительный код, оптимизированный для больших массивов, и могут быть именно тем, что вам нужно.

в качестве полезного примера, для универсального объекта обработки файлов, который использует эффективный для памяти подход, пригодный для итераторов, вы, возможно, захотите проверить код обработки фрагмента файла django: http://code.djangoproject.com/browser/django/trunk/django/core/files/base.py.

0 голосов
/ 28 февраля 2009

join выглядит нормально, если вам действительно нужно собрать всю строку вместе, но тогда вы все равно просто сохраните все это в ОЗУ. В такой ситуации я бы попытался выяснить, есть ли способ обработать каждую часть строки, а затем отбросить обработанную часть, так что вам нужно хранить только фиксированное количество байтов в памяти за раз. В этом, как правило, смысл подхода обратного вызова. (Если вы можете одновременно обрабатывать только часть чанка, используйте буфер как очередь для хранения необработанных данных.)

0 голосов
/ 28 февраля 2009

В python3 bytes объекты отличаются от str, но я не знаю причин, почему с этим что-то не так.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...