sto implementando un algoritmo in Python utilizzando Biopython. Ho diversi allineamenti (serie di sequenze di uguale lunghezza) memorizzati nei file FASTA. Ogni allineamento contiene tra 500 e 30000 seq e ciascuna sequenza ha una lunghezza di circa 17000 elementi. Ogni sequenza è memorizzata come oggetto Bio.SeqRecord.SeqRecord (controllare lo SeqRecord object's API documentation per ulteriori informazioni) che contiene non solo la sequenza ma anche alcune informazioni a riguardo. L'ho letto da disco usando Bio.AlignIO.read() (controllare la AlignIO module's API documentation per maggiori informazioni), che restituisce un oggetto MultipleSeqAlignment:Cercando di parallelizzare un algoritmo di pitone con multithreading e evitare restrizioni GIL
seqs = AlignIO.read(seqs_filename, 'fasta')
len_seqs = seqs.get_alignment_length()
stats = {'-': [0.0] * len_seqs, 'A': [0.0] * len_seqs,
'G': [0.0] * len_seqs, 'C': [0.0] * len_seqs,
'T': [0.0] * len_seqs}
includo questo schizzo per motivi di chiarezza:
Perché voglio paralizzare l'analisi dell'allineamento, assegnando a ciascuna CPU disponibile un frammento di esso utilizzando lo threading module (ulteriori dettagli sul motivo per cui ho preso questa decisione in seguito):
La variabile stats è una variabile condivisa in cui memorizzo alcune informazioni sull'analisi (come si può vedere nel primo frammento di codice). Poiché ogni CPU modifica le diverse posizioni di questa variabile condivisa , penso che non sia necessario alcun controllo di accesso né alcuna primitiva di sincronizzazione. Il motivo principale per cui sto usando thread anziché processi è perché Voglio evitare di copiare l'intero oggetto MultipleSeqAlignment per ogni CPU. Ho fatto qualche ricerca e ho trovato some stackoverflow posts su questo.
Ho anche letto alcune informazioni sulla "temuta" Python Interpreter Lock Globale (GIL) (ho trovato grande informazioni sia a stackoverflow e programmers al cambio pila), ma non sono ancora sicuro al 100% se il mio algoritmo è interessato da questo. Per quanto ne so, sto caricando le sequenze in memoria una alla volta, facendo così IO su ogni iterazione. Questo è il motivo per cui penso che sia una buona idea usare i thread come indicato in this stackoverflow post che ho già menzionato prima. La struttura di base delle analisi (che ciascun thread è in esecuzione) simile a questa:
for seq in seqs:
num_column = start_column
for column in seq.seq[start_column:end_column].upper():
# [...]
try:
stats[elem][num_column] = get_some_info(column)
except TypeError:
raise TypeError(('"stats" argument should be a '
'dict of lists of int'))
ho fatto alcuni test di performance che utilizzano il timeit module e the time command utilizzando gli argomenti -f "% e% M" di non controllare solo il tempo reale trascorso (in secondi) ma anche la dimensione massima residente del processo durante la sua durata (in Kbyte). Sembra che il tempo di esecuzione utilizzando i thread sia il tempo di esecuzione dell'implementazione sequenziale diviso per il numero di thread. Per la dimensione massima residente non riesco ancora a trovare un motivo.
Se avete altri suggerimenti su prestazioni o chiarezza, li apprezzerei molto.
Grazie in anticipo.
Per quanto riguarda la reputazione, la cosa migliore che potevo fare era di sviare la domanda, ora ho 10+ reputazioni, suppongo, ma mi dispiace non posso aiutarti con la domanda – ZdaR
Grazie @Anmol_uppal! Ho appena modificato la domanda :-) –