замена readinto ()? - PullRequest
       33

замена readinto ()?

2 голосов
/ 20 марта 2012

Копирование файла с использованием прямого подхода в Python обычно выглядит следующим образом:

def copyfileobj(fsrc, fdst, length=16*1024):
    """copy data from file-like object fsrc to file-like object fdst"""
    while 1:
        buf = fsrc.read(length)
        if not buf:
            break
        fdst.write(buf)

(кстати, этот фрагмент кода взят из shutil.py).

К сожалениюэто имеет недостатки в моем особом случае использования (включая многопоточность и очень большие буферы) [Часть, выделенная курсивом, добавленная позже] .Во-первых, это означает, что при каждом вызове read () выделяется новый фрагмент памяти, и когда buf перезаписывается на следующей итерации, эта память освобождается только для того, чтобы снова выделить новую память для той же цели.Это может замедлить весь процесс и создать ненужную нагрузку на хост.

Чтобы избежать этого, я использую метод file.readinto (), который, к сожалению, задокументирован как устаревший и не используется.:

def copyfileobj(fsrc, fdst, length=16*1024):
    """copy data from file-like object fsrc to file-like object fdst"""
    buffer = array.array('c')
    buffer.fromstring('-' * length)
    while True:
        count = fsrc.readinto(buffer)
        if count == 0:
            break
        if count != len(buffer):
            fdst.write(buffer.toString()[:count])
        else:
            buf.tofile(fdst)

Мое решение работает, но есть и два недостатка: во-первых, readinto () не должен использоваться.Это может уйти (говорит документация).Во-вторых, с readinto () я не могу решить, сколько байтов я хочу прочитать в буфер, а с buffer.tofile () я не могу решить, сколько я хочу записать, следовательно, громоздкий особый случай для последнего блока (что также неоправданнодорогой).

Я посмотрел на array.array.fromfile (), но его нельзя использовать для чтения "все, что есть" (читает, затем выдает EOFError и не передает количество обработанныхПредметы).Кроме того, это не решение конечной особой проблемы.

Есть ли правильный способ сделать то, что я хочу сделать?Может быть, я просто пропускаю простой класс буфера или аналогичный класс, который делает то, что я хочу.

Ответы [ 2 ]

3 голосов
/ 20 марта 2012

Этот фрагмент кода взят из shutil.py

. Это стандартный библиотечный модуль.Почему бы просто не использовать его?

Во-первых, это означает, что при каждом вызове read () выделяется новый фрагмент памяти, а когда в следующей итерации перезаписывается buf, эта память освобождается только для выделенияновая память снова для той же цели.Это может замедлить весь процесс и создать ненужную нагрузку на хост.

Это незначительно по сравнению с усилиями, необходимыми для фактического захвата страницы данных с диска.

2 голосов
/ 20 марта 2012

Обычный код Python не потребовался бы для таких настроек, как этот - однако, если вам действительно нужна вся эта настройка производительности для чтения файлов из кода Python (например, вы переписываете какой-то серверный код, который вы написали и уже работаете для производительности или использования памяти) Я бы предпочел вызывать ОС напрямую, используя ctypes - таким образом, копирование выполнялось на низком уровне, как я хочу.

Может даже оказаться, что простой вызов исполняемого файла "cp" в качестве внешнего процесса в вашем случае будет менее затруднительным (и для вас будут использованы все преимущества всех оптимизаций на уровне ОС и файловой системы).

...