2014-12-29 5 views
6


Ich ist die Umsetzung einen Algorithmus in PythonBiopython verwenden. Ich habe mehrere Ausrichtungen (Sätze von Sequenzen gleicher Länge) in FASTA Dateien gespeichert. Jede Ausrichtung enthält zwischen 500 und 30000 Seq. Und jede Sequenz ist etwa 17000 Elemente lang. Jede Sequenz wird als Bio.SeqRecord.SeqRecord Objekt gespeichert (überprüfen Sie die SeqRecord object's API documentation für weitere Informationen), die nicht nur die Sequenz, sondern auch einige Informationen darüber enthält. Ich las es von der Festplatte mit Bio.AlignIO.read() (überprüfen Sie die AlignIO module's API documentation für weitere Informationen), die gibt ein MultipleSeqAlignment Objekt:Des Versuch, einen Python-Algorithmus parallelisieren Multithreading verwenden und die Vermeidung von GIL Einschränkungen

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} 


Ich schließe diese Skizze aus Gründen der Übersichtlichkeit: enter image description here


Weil ich mag paralelize die Analyse der Ausrichtung, ich Zuordnung zu jedem verfügbaren CPU ein Fragment davon mit der threading module (mehr Details über, warum ich diese Entscheidung später getroffen habe):

Die Statistikvariable ist eine gemeinsame Variable, in der ich einige Informationen über die Analyse speichere (wie Sie im ersten Codeausschnitt sehen können). Da jede CPU verschiedene Positionen dieser geteilten Variablen ändern wird, denke ich, dass es keine Notwendigkeit der Zugriffssteuerung noch irgendein Synchronisationsgrundelement gibt. Der Hauptgrund, warum ich Threads anstelle von Prozessen verwende, ist, weil Ich möchte vermeiden, das ganze MultipleSeqAlignment Objekt für jede CPU zu kopieren. Ich habe etwas Forschung getan und some stackoverflow posts darüber gefunden.

Ich habe auch einige Informationen über die „gefürchtete“ Python Globaler Interpreter Lock (GIL) lesen (I große Info gefunden sowohl bei stackoverflow und programmers bei Stapelaustausch) aber Ich bin immer noch nicht zu 100% sicher, ob mein Algorithmus ist davon betroffen. Soweit ich weiß, lade ich nacheinander Sequenzen in den Speicher und mache so IO bei jeder Iteration. Deshalb denke ich, dass es eine gute Idee ist, Threads zu verwenden, wie in this stackoverflow post erwähnt wurde, die ich bereits erwähnt habe. Die Grundstruktur der Analyse sieht etwa so aus (die jeder Thread ausgeführt wird):

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')) 

ich einige Performance-Tests durchgeführt haben die timeit module und the time command unter Verwendung der Argumente -f „% e% M“ können Sie nicht überprüfen nur die verstrichene Echtzeit (in Sekunden), aber auch die maximale Resident-Set-Größe des Prozesses während seiner Lebensdauer (in KB). Es scheint, dass die Ausführungszeit mit Threads die Ausführungszeit der sequenziellen Implementierung geteilt durch die Anzahl der Threads ist. Für die maximale Resident-Set-Größe kann ich immer noch kein Muster finden.


Wenn Sie irgendwelche anderen Vorschläge über Leistung oder Klarheit haben, würde ich sie sehr schätzen.


Vielen Dank im Voraus.

+1

Soweit Ihr Ruf in Betracht gezogen wurde, war das Beste, was ich tun konnte, war Ihre Frage zu verbessern, jetzt haben Sie 10+ Ruf ich denke, aber sorry kann ich Ihnen nicht helfen mit Frage – ZdaR

+0

Dank @Annol_uppal! Ich habe gerade die Frage bearbeitet :-) –

Antwort

2

Threading wird Ihnen nicht helfen, wenn Sie einen vermutlich CPU-intensiven Algorithmus über einige Daten ausführen möchten.Versuchen Sie einmal, in das Modul multiprocessing zu schauen, mit dem ich bei der Arbeit an einem Projekt, das in einem gescannten Bild mit 100 MB eine spezielle OCR durchgeführt hat, sehr erfolgreich war.

Betrachten Sie dies das Shared Memory-Ausgabe für die Lösung:

from multiprocessing import Pool 

def f(x): 
    return x*x 

if __name__ == '__main__': 
    pool = Pool(processes=4)    # start 4 worker processes 
    result = pool.apply_async(f, [10]) # evaluate "f(10)" asynchronously 
    print result.get(timeout=1)   # prints "100" unless your computer is *very* slow 
    print pool.map(f, range(10))   # prints "[0, 1, 4,..., 81]" 

Werfen Sie einen Blick auf pool.imap() und pool.apply_async().

Hoffnung, die geholfen hat.

+0

Bitte erklären Sie, warum Threading nicht hilft, da eine der primären Verwendungen von Threading darin besteht, die Verarbeitung mit mehr als einem Kern gleichzeitig durch ein Programm zu erlauben. –

+0

Es ist, aber in Python Threading ist nicht wirklich gleichzeitig, wenn es darum geht, die CPU-Leistung zu teilen, ist es gut für I/O, Networking und ähnliche Dinge. Bibliotheken wie "multiprocessing" und "subprocess" gibt es aus gutem Grund – whiterock

+0

Nun, das gilt für CPython sowieso. Und das stimmt wegen der GIL, die der Fragesteller versucht herumzukommen. Wenn es also in CPython unmöglich ist, die GIL zu umgehen, wäre es nett, wenn es eine Erklärung dafür gäbe. Übrigens gibt es die Module 'multiprocessing' und' subprocess' auch aus anderen Gründen, wie zum Beispiel die Optimierung von Dingen, die zuvor von einer Reihe von OS-abhängigen Funktionen im 'os' Modul behandelt wurden. –

Verwandte Themen