Python — повышение производительности при построчном чтении плоского файла

#python #python-3.x

Вопрос:

У меня есть большой .txt файл, который я хочу читать по одной строке за раз (вместо того, чтобы читать все это в память, чтобы избежать проблем с нехваткой памяти), а затем извлекать все уникальные символы, присутствующие в файле. У меня есть приведенный ниже код, который хорошо работает для небольших файлов, но когда я запускаю его в большом файле (это те файлы, которые мне обычно нужны для выполнения упражнения), он выполняется очень медленно, например, около 1 часа для файла объемом 10 ГБ. Может кто-нибудь, пожалуйста, подсказать, как я могу улучшить производительность, например, путем перестановки выполняемых операций, избегая повторяющихся запусков или используя более быстрые функции.

Спасибо

 def flatten(t):
'''Flatten list of lits'''
    return [item for sublist in t for item in sublist]

input_file = r'C:large_text_file.txt'
output_file = r'C:char_set.txt'

#Parameters
case_sensitive = False
remove_crlf = True

#Extract all unique characters from file
charset = []
with open(input_file, 'r') as infile:
    for line in infile:
        if remove_crlf:
            charset.append(list(line.rstrip())) #remove CRLF
        else:
            charset.append(list(line))
        
        charset = flatten(charset) #flatten the list of lists

        if not(case_sensitive):
            charset = (map(lambda x: x.upper(), charset)) #convert to upper case

        charset = list(dict.fromkeys(charset)) #remove duplicates

charset.sort(key=None, reverse=False) #sort character set in ascending order

infile.close() #close the input file

#Output the charater set
with open(output_file, 'w') as f:
    for char in charset:
        f.write(char)
 

Ответ №1:

Вы можете очень упростить это, чтобы сделать его линейным:

 charset = set()  # use a real set!
with open(input_file, 'r') as infile:
    for line in infile:
        if remove_crlf:
            line = line.strip()
        if not case_sensitive:
            line = line.upper()
        charset.update(line)

with open(output_file, 'w') as f:
    for char in sorted(charset):
        f.write(char)
 

Что сделало его квадратичным, были ли все эти строки:

 charset = flatten(charset) #flatten the list of lists
charset = map(lambda x: x.upper(), charset)
charset = list(dict.fromkeys(charset))
 

где вы продолжаете выполнять операции с постоянно растущим списком, а не только с текущей строкой.

Некоторая документация:

Комментарии:

1. Спасибо! Позвольте мне попробовать это сейчас. Что такое difference_update() ?

2. Добавлены некоторые ссылки на документацию. Конечно, это должно было быть update . Исправлено.

3. Это работает отлично, выполнил задание за 3 минуты! Спасибо! Только одно обновление — charset.update(line.strip()) должно быть обновлено charset.update(line) , чтобы CRLF удалялся только тогда, когда remove_crlf для параметра установлено значение True .

4. Ах, конечно. Вставил условие позже и не удалил начальную полосу.