У меня проблема с памятью, программа работает хорошо и быстро на моем рабочем столе MAC (16 ГБ), когда база данных, которую я сжимаю, при размере базы данных менее 10 ГБ, поэтому сжатый словарь хорошо согласуется с моими характеристиками памяти , Недавно я попытался сжать файл базы данных размером 40 ГБ, и вот тут я начал осознавать проблему. Код работает нормально до конца и выдает все ожидаемые файлы, но не завершается после выполнения всего кода. Кажется, что в мониторе активности максимальный объем памяти, который использует код, составляет 13,84 ГБ. Это не освобождает память в конце, и мне приходится каждый раз заставлять его (ctrl + C) останавливать код. Интересно, что в коде есть два режима: либо сжатие БД, либо использование предварительно сжатого. Проблема более глубока в режиме сжатия, в то время как в режиме предварительного сжатия, когда я восстанавливаю словарь из txt-файла, проблема возникает, но в меньшей степени (для завершения кода требуется 1 минута), в то время как для режима сжатия это может занять 10- 15 минут, чтобы освободить память или никогда не кончится. Мой вопрос, как улучшить код, чтобы он не зависал в конце вечно? и в чем разница между двумя режимами (по памяти)?
Идея программы проста. Он сжимает базу данных, используя совпадение строк (ключ) и добавляя идентификаторы в список в качестве значения в dict. Затем вы можете предоставить запрос для проверки количества идентификаторов, связанных с любой строкой (ключом). Я ожидаю, что проблема сильно загружена память. Я пытался использовать многопроцессорность, но на самом деле использование памяти увеличилось, а сжатие заняло гораздо больше времени, и это не помогло, но, возможно, я использую его неправильно, поскольку это мой первый раз (закомментировано в коде). Код был написан не как функции, а как попытка решить проблему, я создал функции, которые пытаются автоматически выбрасывать все объекты (используя python gc) после завершения функции, не указывая (ссылаясь) на них.
#!/usr/bin/env python3
import os
import sys
from collections import defaultdict
import time
import argparse
#import multiprocessing
START_TIME = time.time()
PARSER = argparse.ArgumentParser(prog="xzxzxz.py",description="xzxzxz",)
GROUP = PARSER.add_mutually_exclusive_group()
GROUP.add_argument("-m","--mkdatabase",type=str,help="provide path to file or a folder for compression",)
GROUP.add_argument("-d","--database",type=str,help="provide path to compressed database",)
PARSER.add_argument("-v","--version",help="print version exit",action="version",version="%(prog)s 2.0",)
PARSER.add_argument("query_file", type=str, help="Query file/s to analyze")
ARGS = PARSER.parse_args()
#####variables######
SEQUENCES_DICT = {}
TIMESTR = time.strftime("%Y%m%d_%H%M%S")
#####create results folder######
os.mkdir("xzxzxz_results_v2_" + TIMESTR)
RESULTS_FOLDER = "./xzxzxz_results_v2_{}/".format(TIMESTR)
print("created results folder({})".format(RESULTS_FOLDER))
##### files to be processed######
QUERY = ARGS.query_file
QUERY_LIST = []
try:
for file in os.listdir(QUERY):
if file.endswith(".faa"):
QUERY_LIST.append(QUERY + file)
except:
if QUERY.endswith(".faa"):
QUERY_LIST.append(QUERY)
#####database files to be compressed######
if ARGS.mkdatabase:
DATABASE_FILES = ARGS.mkdatabase
DATABASE_FILES_LIST = []
try:
for file in os.listdir(DATABASE_FILES):
if file.endswith(".faa"):
DATABASE_FILES_LIST.append(DATABASE_FILES + file)
except:
if DATABASE_FILES.endswith(".faa"):
DATABASE_FILES_LIST.append(DATABASE_FILES)
#####Run database for first time#####
def DB_compressor(DATABASE_FILES2_LIST):
protein_counter = 0
DICT_DB = defaultdict(list)
DB_SEQUENCE_STRING = ""
DB_SEQUENCE_INFO = ""
for DATABASE_FILE2 in DATABASE_FILES2_LIST:
DATABASEFILE_OBJECT2 = open(DATABASE_FILE2, "r")
for line in DATABASEFILE_OBJECT2:
line = line.rstrip()
if line.startswith(">"):
protein_counter += 1
if len(DB_SEQUENCE_STRING) > 0:
DICT_DB[DB_SEQUENCE_STRING].append(DB_SEQUENCE_INFO)
DB_SEQUENCE_STRING = ""
DB_SEQUENCE_INFO = line.lstrip(">")
else:
DB_SEQUENCE_STRING += line
DICT_DB[DB_SEQUENCE_STRING].append(DB_SEQUENCE_INFO)
DATABASEFILE_OBJECT2.close()
return DICT_DB
#############################
def Match(DICT_DB2):
for ptn_seq2 in DICT_DB2:
ptn_seq_ids_list2 = DICT_DB2[ptn_seq2]
ptn_seq_score2 = len(ptn_seq_ids_list2)
ptn_seq_ids_list2.append(str(ptn_seq_score2))
return DICT_DB2
###################
SEQUENCES_DICT_DB = DB_compressor(DATABASE_FILES_LIST)
SEQUENCES_DICT_DB = Match(SEQUENCES_DICT_DB)
##########Multiprocessing trial##########
#p = multiprocessing.Pool(1)
#SEQUENCES_DICT_DB = p.map(DB_compressor, [DATABASE_FILES_LIST])[0]
#p.terminate()
#p.join()
##########################
#z = multiprocessing.Pool(1)
#SEQUENCES_DICT_DB = z.map(Match, [SEQUENCES_DICT_DB])[0]
#z.terminate()
#z.join()
#####Save database for first time as txt file#####
if ARGS.mkdatabase:
try:
TXT_FILE_NAME = (RESULTS_FOLDER + ARGS.mkdatabase.split(".faa")[0]
+ "_compressed_db_" + TIMESTR + ".txt")
OUTPUT_FILE_DB = open(TXT_FILE_NAME, "w")
for record in SEQUENCES_DICT_DB:
OUTPUT_FILE_DB.write(
"{}\t{}\n".format(record, "._/".join(SEQUENCES_DICT_DB[record])))
OUTPUT_FILE_DB.close()
print(
"saved database of {} strings as txt file in {:.3f} seconds".format(
len(SEQUENCES_DICT_DB), time.time() - START_TIME))
except:
print("cannot save compressed database")
#####load database file#########
if ARGS.mkdatabase:
print("As you just compressed a database using -m, it will be used")
elif ARGS.database:
if ARGS.database.endswith(".txt"):
SEQUENCES_DICT = {}
TXT_DB_FILEOBJECT = open(ARGS.database, "r")
print("opened previously created database in {:.3f} seconds".format(time.time() - START_TIME))
for line in TXT_DB_FILEOBJECT:
line = line.rstrip()
seq, ids = line.split("\t")
listids = ids.split("._/")
SEQUENCES_DICT[seq] = listids
if bool(SEQUENCES_DICT):
print("processed database to dictionary in {:.3f} seconds".format(time.time() - START_TIME))
#########meat###########
report_list = ["ptn", "len", "func", "seq", "score",
"group", "gp_number", "number","minimum", "maximum", "average", "Frequency", "Index"]
for QUERYFILE in QUERY_LIST:
QUERYFILE_OBJECT = open(QUERYFILE, "r")
file_report = (RESULTS_FOLDER
+ (QUERYFILE.rsplit("/", 1)[-1]).split(".faa")[0]
+ "_xzxzxz_report_v2.txt")
output_file_report = open(file_report, "w")
output_file_report.write("{}\n".format("\t".join(report_list[:5])))
processed_counter = 0
sequence_info = ""
sequence_string = ""
for line in QUERYFILE_OBJECT:
line = line.rstrip()
if line.startswith(">"):
if len(sequence_string) > 0:
processed_counter += 1
try:
ids_list = SEQUENCES_DICT_DB[sequence_string]
try:
function = ids_list[0].split(' ',1)[1] #addition8
except:
function = ids_list[0]
query_sequence_info = [sequence_info,str(len(sequence_string)),
function,sequence_string]
match_score = ids_list[-1]
output_file_report.write("{}\t{}\n".format(
"\t".join(query_sequence_info),match_score))
except:
query_sequence_info = [sequence_info,str(len(sequence_string)),
'NA',sequence_string]
output_file_report.write("{}\t0\n".format(
"\t".join(query_sequence_info)))
sequence_string = ""
sequence_info = line.lstrip(">")
else:
sequence_string += line
processed_counter += 1
try:
ids_list = SEQUENCES_DICT_DB[sequence_string]
try:
function = ids_list[0].split(' ',1)[1] #addition8
except:
function = ids_list[0]
query_sequence_info = [sequence_info,str(len(sequence_string)),
function,sequence_string]
match_score = ids_list[-1]
output_file_report.write("{}\t{}\n".format(
"\t".join(query_sequence_info),match_score))
except:
query_sequence_info = [sequence_info,str(len(sequence_string)),
'NA',sequence_string]
output_file_report.write("{}\t0\n".format(
"\t".join(query_sequence_info)))
print("processed {} proteins of {} in {:.3F}".format(
processed_counter,(QUERYFILE.rsplit("/", 1)[-1]).split(".faa")[0],
time.time() - START_TIME,))
output_file_report.close()
QUERYFILE_OBJECT.close()
print("Done in --- {:.3f} seconds ---".format(time.time() - START_TIME))
#The code never ends or takes too long time after this line to end.
$ xzxzxz.py -m NCTC8325.faa NCTC8325.faa
созданная папка результатов (./ xzxzxz_results_v2_20190703_160114 /)
сохраненная база данных 2887 белков в виде txt файла за 0.032 секунды
Поскольку вы только что сжали базу данных с помощью -m, она будет использоваться
обработано 2892 белка NCTC8325 в 0,062
Совершено за --- 0.064 секунды ---
Код никогда не заканчивается или занимает слишком много времени после завершения этой строки (что завершает выполнение кода).