2012-02-27 4 views
5

Ho fatto una domanda simile prima, ma non ho avuto alcuna risposta utile quindi cercherò di rendere le cose più chiare.Multiprocessing e Multithreading

Quello che sto cercando è di eseguire un approccio multithread o preferibilmente multiprocessing ad un certo comando linux. Se qualcuno ha familiarità con Picard, sto volendo eseguire una versione precedente su un file bam e allo stesso tempo eseguire una versione più recente sullo stesso file bam. L'idea è di testare quanto più veloce è la versione più recente e se dà lo stesso risultato.

Il mio problema principale è che non ho idea di come implementare la multiprocessing su un comando Popen. Per esempio.

cmd1 = ['nice', 'time', 'java', '-Xmx6G', '-jar', '/comparison/old_picard/MarkDuplicates.jar', 'I=/comparison/old.bam', 'O=/comparison/old_picard/markdups/old.dupsFlagged.bam', 'M=/comparison/old_picard/markdups/old.metrics.txt', 'TMP_DIR=/comparison', 'VALIDATION_STRINGENCY=LENIENT', 'ASSUME_SORTED=true'] 
cmd2 = ['nice', 'time', 'java', '-Xmx6G', '-jar', '/comparison/new_picard/MarkDuplicates.jar', 'I=/comparison/new.bam', 'O=/comparison/new_picard/markdups/new.dupsFlagged.bam', 'M=/comparison/new_picard/markdups/new.metrics.txt', 'TMP_DIR=/comparison', 'VALIDATION_STRINGENCY=LENIENT', 'ASSUME_SORTED=true'] 

c1 = subprocess.Popen(cmd1, stdout=subprocess.PIPE) 
c2 = subprocess.Popen(cmd2, stdout=subprocess.PIPE) 

E poi ho una funzione timer:

def timeit(c): 
    past = time.time() 
    results = [c.communicate()] 
    present = time.time() 
    total = present - past 
    results.append(total) 
    return results 

Quello che voglio fare è questo:

p = Process(target=timeit, args=(c1,c2)) 
p.start() 
p.join() 

Tuttavia ottengo "Popen non oggetto iterabile" errore. Qualcuno ha un'idea migliore di quella che ho adesso? Non voglio andare in una direzione completamente diversa solo per colpire un altro muro. In sintesi voglio eseguire c1 su una cpu e c2 sull'altro allo stesso tempo, per favore aiuto!

+0

Perché vuoi eseguirli contemporaneamente? Dubito che otterrai risultati significativi da questo. –

+4

Hai considerato di eseguirli in sequenza, in modo da poter effettivamente simulare il processo stesso? La CPU non è l'unica risorsa condivisa, quindi se si tratta di un'operazione che richiede un utilizzo intensivo della memoria o del disco, è possibile che un processo o un thread stia vincendo e abbia l'aspetto di essere più veloce. – Jordan

risposta

4

Invece di passare l'subprocess.Popen (che li serialmente invece verrà eseguito in parallelo quando viene inizialmente definita), il passaggio comando:

import time 
import subprocess 
from multiprocessing import Process 

cmd1 = ['nice', 'time', 'java', '-Xmx6G', '-jar', '/comparison/old_picard/MarkDuplicates.jar', 'I=/comparison/old.bam', 'O=/comparison/old_picard/markdups/old.dupsFlagged.bam', 'M=/comparison/old_picard/markdups/old.metrics.txt', 'TMP_DIR=/comparison', 'VALIDATION_STRINGENCY=LENIENT', 'ASSUME_SORTED=true'] 
cmd2 = ['nice', 'time', 'java', '-Xmx6G', '-jar', '/comparison/new_picard/MarkDuplicates.jar', 'I=/comparison/new.bam', 'O=/comparison/new_picard/markdups/new.dupsFlagged.bam', 'M=/comparison/new_picard/markdups/new.metrics.txt', 'TMP_DIR=/comparison', 'VALIDATION_STRINGENCY=LENIENT', 'ASSUME_SORTED=true'] 

def timeit(cmd): 
    print cmd 
    past = time.time() 
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE) 
    results = [p.communicate()] 
    present = time.time() 
    total = present - past 
    results.append(total) 
    return results 

p1 = Process(target=timeit, args=(cmd1,)) 
p2 = Process(target=timeit, args=(cmd2,)) 

for p in (p1, p2): 
    p.start() 
for p in (p1, p2): 
    p.join() 

ETA: Mentre la soluzione di cui sopra è il modo per fare multiprocessing in generale, @Jordan ha perfettamente ragione a non dover utilizzare questo approccio in tempo per due versioni del software. Perché non eseguirli in sequenza?

+0

Queste attività potrebbero richiedere molto tempo per essere eseguite, quindi utilizzerei una macchina host condivisa con più potenza per eseguirle. Se li eseguivo in sequenza (diciamo prima la versione precedente) e il carico del processore della macchina era basso, e poi in alcune ore la nuova versione di picard era in esecuzione, ma più utenti avevano aggiunto attività all'host causandole un carico elevato . Quindi la seconda attività rallenterebbe solo a causa dell'altro traffico. Quindi non avrebbe senso cronometrarli, perché le statistiche non sarebbero in condizioni uguali. –

+0

come mai non hai inserito p.join() nello stesso ciclo per p.start()? –

+0

anche il tuo un genio e ti amo, ha funzionato. –

0

penso che qualcosa del genere dovrebbe funzionare:

p1 = Process(target=timeit, args=(c1,)) 
p2 = Process(target=timeit, args=(c2,)) 
p1.start() 
p2.start() 
p1.join() 
p2.join() 

Non so dove l'errore di iterazione è però (quale linea è?).

Inoltre, penso che faresti meglio a eseguirli separatamente. Quando li esegui insieme, corri il rischio che a un processo venga dato più tempo della CPU e sembrino essere più veloci, anche quando non lo è.