Как я могу сделать свой скрипт Python быстрее?

Я довольно новичок в Python, и я написал (возможно, очень уродливый) скрипт, который должен случайно выбрать подмножество последовательностей из файла fastq. Fastq-файл хранит информацию в блоках по четыре строки. Первая строка в каждом блоке начинается с символа «@». Файл fastq, который я использую в качестве входного файла, составляет 36 ГБ, содержащий около 14 000 000 строк.

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

parser = argparse.ArgumentParser() parser.add_argument("infile", type = str, help = "The name of the fastq input file.", default = sys.stdin) parser.add_argument("outputfile", type = str, help = "Name of the output file.") parser.add_argument("-n", help="Number of sequences to sample", default=1) args = parser.parse_args() def sample(): linesamples = [] infile = open(args.infile, 'r') outputfile = open(args.outputfile, 'w') # count the number of fastq "chunks" in the input file: seqs = subprocess.check_output(["grep", "-c", "@", str(args.infile)]) # randomly select n fastq "chunks": seqsamples = random.sample(xrange(0,int(seqs)), int(args.n)) # make a list of the lines that are to be fetched from the fastq file: for i in seqsamples: linesamples.append(int(4*i+0)) linesamples.append(int(4*i+1)) linesamples.append(int(4*i+2)) linesamples.append(int(4*i+3)) # fetch lines from input file and write them to output file. for i, line in enumerate(infile): if i in linesamples: outputfile.write(line) 

Для grep-шага практически нет времени, но спустя более 500 минут сценарий все еще не начал записываться в выходной файл. Поэтому я полагаю, что это один из шагов между grep и последним for-loop, который занимает такое долгое время. Но я не понимаю, какой именно шаг, и что я могу сделать, чтобы ускорить его.

    4 Solutions collect form web for “Как я могу сделать свой скрипт Python быстрее?”

    В зависимости от размера linesamples , if i in linesamples займет много времени с тех пор, как вы просматриваете список для каждой итерации через infile . Вы можете преобразовать это в set чтобы улучшить время поиска. Кроме того, enumerate не очень эффективно – я заменил его конструкцией line_num которую мы увеличиваем на каждой итерации.

     def sample(): linesamples = set() infile = open(args.infile, 'r') outputfile = open(args.outputfile, 'w') # count the number of fastq "chunks" in the input file: seqs = subprocess.check_output(["grep", "-c", "@", str(args.infile)]) # randomly select n fastq "chunks": seqsamples = random.sample(xrange(0,int(seqs)), int(args.n)) for i in seqsamples: linesamples.add(int(4*i+0)) linesamples.add(int(4*i+1)) linesamples.add(int(4*i+2)) linesamples.add(int(4*i+3)) # make a list of the lines that are to be fetched from the fastq file: # fetch lines from input file and write them to output file. line_num = 0 for line in infile: if line_num in linesamples: outputfile.write(line) line_num += 1 outputfile.close() 

    Вы сказали, что grep заканчивается довольно быстро, поэтому в этом случае вместо того, чтобы просто использовать grep для подсчета появления @, grep выводит байтовые смещения каждого символа @, который он видит (используя параметр -b для grep). Затем используйте random.sample чтобы выбрать, который когда-либо блокирует вас. После того, как вы выбрали смещения байтов, которые вы хотите, используйте infile.seek чтобы перейти к каждому смещению байта и распечатать 4 строки оттуда.

    Попробуйте распараллелить свой код. Я имею в виду это. У вас есть 14 000 000 строк ввода.

    1. Работайте с grep и сначала отфильтруйте свои строки, и напишите в файл filterInput.txt
    2. Разделите свой filterInput на 10.000-100.000 строк файлов, таких как filterInput001.txt, filterInput002.txt
    3. Работайте с нашим кодом в этих файлах с разделом. Напишите свой вывод в разные файлы, такие как output001.txt, output002.txt
    4. Объедините результаты в качестве последнего шага.

    Так как ваш код не работает вообще. Вы также можете запустить свой код на эти отфильтрованные входы. Ваш код проверяет наличие файлов filterInput и будет понимать, на каком этапе он был, и возобновить с этого шага.

    Вы также можете использовать несколько процессов python таким образом (после шага 1), используя ваши оболочки или потоки python.

    Вы можете использовать алгоритм выборки коллектора . С помощью этого алгоритма вы читаете данные только один раз (нет необходимости заранее подсчитывать строки файла), чтобы вы могли передавать данные через ваш скрипт. На странице Википедии есть пример кода python.

    Существует также реализация C для быстрой выборки в seqtk Хэн Ли.

    Python - лучший язык программирования в мире.