Скрипт Python никогда не завершается после выполнения всего кода и файлов, созданных из-за ада подкачки памяти - PullRequest
0 голосов
/ 03 июля 2019

У меня проблема с памятью, программа работает хорошо и быстро на моем рабочем столе 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 секунды ---

Код никогда не заканчивается или занимает слишком много времени после завершения этой строки (что завершает выполнение кода).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...