Python writelines () и write () огромная разница во времени
я работал над сценарием, который читал папку с файлами (каждый размером от 20 МБ до 100 МБ), изменяет некоторые данные в каждой строке и записывает обратно в копию файла.
with open(inputPath, 'r+') as myRead:
my_list = myRead.readlines()
new_my_list = clean_data(my_list)
with open(outPath, 'w+') as myWrite:
tempT = time.time()
myWrite.writelines('n'.join(new_my_list) + 'n')
print(time.time() - tempT)
print(inputPath, 'Cleaning Complete.')
при запуске этого кода с файлом 90 MB (~900,000 строк) он напечатал 140 секунд как время, необходимое для записи в файл. Здесь я использовал writelines()
. Поэтому я искал различные способы улучшить скорость записи файлов, и в большинстве статей, которые я читал, он сказал write()
и writelines()
не должно показывать никакой разницы, так как я пишу одну объединенную строку. Я также проверил время, затраченное только на следующее утверждение:
new_string = 'n'.join(new_my_list) + 'n'
и это заняло всего 0,4 секунды, поэтому большое время заняло не из-за создания списка.
Просто попробовать write()
я попробовал этот код:
with open(inputPath, 'r+') as myRead:
my_list = myRead.readlines()
new_my_list = clean_data(my_list)
with open(outPath, 'w+') as myWrite:
tempT = time.time()
myWrite.write('n'.join(new_my_list) + 'n')
print(time.time() - tempT)
print(inputPath, 'Cleaning Complete.')
и он напечатал 2,5 секунды. Почему существует такая большая разница во времени записи файла для write()
и writelines()
даже если это те же данные? Заключаться в следующем нормальное поведение или что-то не так в моем коде? Выходной файл кажется одинаковым для обоих случаев, поэтому я знаю, что нет потери данных.
3 ответов
file.writelines()
ждет типа Iterable строк. Затем он переходит к циклу и вызову file.write()
для каждой строки в массиве. В Python метод делает следующее:
def writelines(self, lines)
for line in lines:
self.write(line)
вы передаете одну большую строку, и строка также является итерацией строк. При итерации вы получаете отдельные символы, строки длины 1. Таким образом, в действительности вы делаете len(data)
отдельные вызовы file.write()
. И это медленно, потому что вы создаете запись буфер по одному символу за раз.
не передавайте ни одной строки в file.writelines()
. Вместо этого передайте список или кортеж или другой iterable.
вы можете отправить отдельные строки с добавленной новой строкой в выражении генератора, например:
myWrite.writelines(line + '\n' for line in new_my_list)
теперь, если вы могли бы сделать clean_data()
a генератор, давая очищенные линии, вы можете передавать данные из входного файла, через генератор очистки данных и в выходной файл без используя больше памяти, чем требуется для буферов чтения и записи, и сколько состояния необходимо для очистки строк:
with open(inputPath, 'r+') as myRead, open(outPath, 'w+') as myWrite:
myWrite.writelines(line + '\n' for line in clean_data(myRead))
кроме того, я бы рассмотрел обновление clean_data()
излучать строк с переносами строк.
в качестве дополнения к ответу Martijn лучшим способом было бы избежать создания списка с помощью join
в первую очередь
просто передайте понимание генератора writelines
, добавив новую строку в конце: нет ненужного выделения памяти и нет цикла (кроме понимания)
myWrite.writelines("{}\n".format(x) for x in my_list)
' write(arg) ' метод ожидает строку в качестве аргумента. Поэтому, как только он позвонит, он будет напрямую писать. это причина намного быстрее.
где, как будто вы используете writelines()
метод, он ожидает список строк в качестве итератора. поэтому, даже если вы отправляете данные в writelines
, Он предполагает, что он получил итератор и пытается перебрать его. поэтому, поскольку это итератор, потребуется некоторое время, чтобы повторить и написать его.
Это понятно ?