Как я могу распараллелить вычисления в файле fasta, где каждый процессор занимает одну последовательность

1

Я не знаю, как распараллелить код в Python, который берет каждую строку файла FASTA и создает некоторую статистику, например, вычисляет содержимое GC. У вас есть несколько советов или библиотек, которые помогут мне сократить время, затрачиваемое на выполнение?

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

#Computing GC Content
from Bio import SeqIO                  
with open('chr1.fa', 'r') as f:
    records = list (SeqIO.parse(f,'fasta'))
    GC_for_sequence=[]
    for i in records:
        GC=0
        for j in i:
            if j in "GC":
                GC+=1
        GC_for_sequence.append(GC/len(i))
    print(GC_for_sequence)

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

Теги:
parallel-processing
multiprocessing
fork
python-multithreading

2 ответа

0

Несколько заметок о вашем существующем коде для начала:

  1. Я бы посоветовал не делать: list (SeqIO.parse(…)) как это приостановит выполнение до тех пор, пока все последовательности не будут загружены в память, вам гораздо лучше (память и общее время выполнения), просто оставив его в качестве итератора и потребляя элементы для работников по мере необходимости

  2. цикл по каждому символу довольно медленный, использование str.count будет намного быстрее

сложив это вместе, вы можете сделать:

from Bio import SeqIO

with open('chr1.fa') as fd:
    gc_for_sequence=[]
    for seq in SeqIO.parse(fd, 'fasta'):
        gc = sum(seq.seq.count(base) for base in "GC")
        gc_for_sequence.append(gc / len(seq))

если это все еще не достаточно быстро, то вы можете использовать multiprocessing модуль, например:

from Bio import SeqIO
from multiprocessing import Pool

def sequence_gc_prop(seq):
    return sum(seq.count(base) for base in "GC") / len(seq)

with open('chr1.fa') as fd, Pool() as pool:
    gc_for_sequence = pool.map(
        sequence_gc_prop,
        (seq.seq for seq in SeqIO.parse(fd, 'fasta')),
        chunksize=1000,
    )

комментарии от Лукаша в основном применяются. другие неочевидные вещи:

  • странный seq.seq for seq in… это убедиться, что мы не собираем ненужные данные
  • Я устанавливаю chunksize довольно большое значение, потому что функция должна быть быстрой, поэтому мы хотим дать детям разумный объем работы, чтобы родительский процесс не тратил все свое время на оркестровку вещей.
  • 0
    Спасибо! Итак, во входных данных внутри функции pool.map (seq.seq для seq в SeqIO.parse (fd, 'fasta')) модуль берет каждую строку моего файла и вычисляет содержимое GC параллельно?
  • 0
    следует сделать! Вы можете запустить top одновременно, чтобы убедиться, что он работает на нескольких процессорах. в догадке: такого рода задачи не очень подходят для параллельной работы, количество полезной работы, которая может быть распределена на каждый процессор, ограничено. Это означает, что основной процесс будет тратить большую часть своего времени на чтение данных и координацию. поможет переосмысление проблемы, например, обработка нескольких файлов одновременно
0

Вот одна идея со стандартным многопроцессорным модулем:

from multiprocessing import Pool
import numpy as np

no_cores_to_use = 4

GC_for_sequence = [np.random.rand(100) for x in range(10)]

with Pool(no_cores_to_use) as pool:
    result = pool.map(np.average, GC_for_sequence)

print(result)

В коде я использовал модуль numpy для имитации списка с некоторым содержанием. pool.map принимает функцию, которую вы хотите использовать в ваших данных, в качестве первого аргумента, а список данных - в качестве второго. Функция, которую вы можете легко определить самостоятельно. По умолчанию он должен принимать один аргумент. Если вы хотите передать больше, используйте functools.partial.

[EDIT] Вот пример, гораздо ближе к вашей проблеме:

from multiprocessing import Pool
import numpy as np

records = ['ACTGTCGCAGC' for x in range(10)]
no_cores_to_use = 4

def count(sequence):
    count = sequence.count('GC')
    return count

with Pool(no_cores_to_use) as pool:
    result = pool.map(count, records)

print(sum(result))
  • 0
    ХОРОШО! Но если я хочу поместить большое количество различных последовательностей, нужно ли мне помещать их в список, подобный тому, который вы сделали в записях?
  • 0
    Из вашего кода это выглядит так, как будто вы начинаете со списка ( list (SeqIO.parse(f,'fasta')) )), поэтому вам не нужно ничего делать.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню