2016-03-17 1 views
2

Я работаю с большими файлами, имеющими несколько миллионов записей каждый (около 2 ГБ распакованных, несколько сотен мегабайт gzip).Вероятная утечка памяти в контуре генератора с помощью islice

Я перебираю записи с islice, что позволяет мне получить небольшую порцию (для отладки и разработки) или все, когда я хочу протестировать код. Я заметил абсурдно большое использование памяти для моего кода, и поэтому я пытаюсь найти утечку памяти в своем коде.

Ниже представлен вывод memory_profiler на парном чтении (где я открываю два файла и записываю их в архив), ТОЛЬКО 10 ** 5 значений (значение по умолчанию становится перезаписанным).

Line # Mem usage Increment Line Contents 
================================================ 
    137 27.488 MiB 0.000 MiB @profile 
    138        def paired_read(read1, read2, nbrofitems = 10**8): 
    139        """ Procedure for reading both sequences and stitching them together """ 
    140 27.488 MiB 0.000 MiB seqFreqs = Counter() 
    141 27.488 MiB 0.000 MiB linker_str = "~" 
    142        #for rec1, rec2 in izip(read1, read2): 
    143 3013.402 MiB 2985.914 MiB for rec1, rec2 in islice(izip(read1, read2), nbrofitems): 
    144 3013.398 MiB -0.004 MiB  rec1 = rec1[9:]       # Trim the primer variable sequence 
    145 3013.398 MiB 0.000 MiB  rec2 = rec2[:150].reverse_complement() # Trim the low quality half of the 3' read AND take rev complement 
    146         #aaSeq = Seq.translate(rec1 + rec2) 
    147        
    148         global nseqs 
    149 3013.398 MiB 0.000 MiB  nseqs += 1 
    150        
    151 3013.402 MiB 0.004 MiB  if filter_seq(rec1, direction=5) and filter_seq(rec2, direction=3): 
    152 3013.395 MiB -0.008 MiB   aakey = str(Seq.translate(rec1)) + linker_str + str(Seq.translate(rec2)) 
    153 3013.395 MiB 0.000 MiB   seqFreqs.update({ aakey : 1 }) 
    154         
    155 3013.402 MiB 0.008 MiB print "========================================" 
    156 3013.402 MiB 0.000 MiB print "# of total sequences: %d" % nseqs 
    157 3013.402 MiB 0.000 MiB print "# of filtered sequences: %d" % sum(seqFreqs.values()) 
    158 3013.461 MiB 0.059 MiB print "# of repeated occurances: %d" % (sum(seqFreqs.values()) - len(list(seqFreqs))) 
    159 3013.461 MiB 0.000 MiB print "# of low-score sequences (<20): %d" % lowQSeq 
    160 3013.461 MiB 0.000 MiB print "# of sequences with stop codon: %d" % starSeqs 
    161 3013.461 MiB 0.000 MiB print "========================================" 
    162 3013.504 MiB 0.043 MiB pprint(seqFreqs.most_common(100), width = 240) 

Код, в общем, делает некоторую фильтрацию записей и отслеживает, сколько раз строка происходит в файле (архивные пару строк в данном конкретном случае).

100 000 строк из 150 символов с целыми значениями в счетчике должны располагаться на вершинах 100 МБ, которые я проверил, используя следующую функцию: @AaronHall.

Учитывая вывод memory_profiler, я подозреваю, что islice не отпускает предыдущие объекты в течение итерации. Поиск в Google приземлился на this bug report, однако он отмечен как разрешенный для Python 2.7, который я сейчас запускаю.

Любые мнения?

EDIT: Я попытался пропустить islice как на комментарий ниже, и использовать цикл как

for rec in list(next(read1) for _ in xrange(10**5)): 

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

Вторая проблема, связанная с поиском и устранением неисправностей, заключалась в том, чтобы проверить, читает и расширяет ли файл gzip.open() файл и поэтому вызывает здесь проблему. Однако запуск сценария в распакованных файлах не имеет значения.

+0

Попробуйте использовать версию [pure Python] (https://docs.python.org/3/library/itertools.html#itertools.islice) для проверки гипотезы утечки. Или просто отпустите 'islice' и используйте счетчик с' if'. –

+0

@SergeiLebedev, как вы это понимаете? is 'islice' не чистый питон? – posdef

+0

Нет, весь модуль 'itertools' реализован в C, [включая] (https://hg.python.org/cpython/file/2.7/Modules/itertoolsmodule.c#l1123) функцию' islice'. –

ответ

2

Обратите внимание, что memory_profiler сообщает только максимальное потребление памяти для каждой строки. Для длинных циклов это может вводить в заблуждение, поскольку первая строка цикла всегда, кажется, сообщает о непропорциональном объеме памяти.

Это потому, что он сравнивает первую строку цикла с потреблением памяти в строке раньше, что было бы не в цикле. Это не означает, что первая строка цикла потребляет 2985 МБ, а скорее, что разница между пиком в памяти внутри цикла на 2985 Мб выше, чем вне цикла.

+0

Спасибо за указатель Фабиан. Как оказалось, утечка не имеет ничего общего с islice вообще, но вызов библиотеки в Biopython. – posdef

Смежные вопросы