2012-02-27 12 views
5

Hice una pregunta similar antes, pero no obtuve ninguna respuesta útil, así que trataré de aclarar las cosas.Multiproceso y multiprocesamiento

Lo que estoy buscando es ejecutar un enfoque multiproceso o preferiblemente de multiprocesamiento a un cierto comando de Linux. Si alguien está familiarizado con Picard, quiero ejecutar una versión anterior en un archivo bam y al mismo tiempo ejecutar una versión más reciente en el mismo archivo bam. La idea es probar cuánto más rápido es la versión más nueva y si da el mismo resultado.

Mi problema principal es que no tengo idea de cómo implementar el multiprocesamiento en un comando de Popen. P.ej.

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) 

y luego tengo una función de temporizador:

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

lo que quiero hacer es lo siguiente:

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

Sin embargo me sale "no Popen objeto iterable" error. ¿Alguien tiene una idea mejor que la que tengo ahora? No quiero ir en una dirección completamente diferente solo para golpear otra pared. En resumen, quiero ejecutar c1 en una CPU y c2 en la otra al mismo tiempo, ¡por favor ayuda!

+0

¿Por qué quieres ejecutarlos al mismo tiempo? Dudo que obtengas resultados significativos de esto. –

+4

¿Ha considerado ejecutarlos secuencialmente, para que pueda imitar el proceso en sí? La CPU no es el único recurso compartido, por lo que si se trata de una operación que requiere mucha memoria o requiere mucho uso de disco, es posible que tenga un proceso o subproceso que resulte ganador y que tenga la apariencia de ser más rápido. – Jordan

Respuesta

4

lugar de pasar el subprocess.Popen (que se extenderá ellos en serie en lugar de en paralelo cuando se define primero), pase el 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: Mientras que la solución anterior es el camino para hacer multiprocesamiento en general, @Jordan tiene razón en que no debes usar este enfoque para sincronizar dos versiones de software. ¿Por qué no ejecutarlos secuencialmente?

+0

Es posible que estas tareas tarden mucho tiempo en ejecutarse, por lo tanto, estaría utilizando una máquina host compartida con más poder para ejecutarlas. Si los ejecuté secuencialmente (digamos primero la versión anterior) y la carga del procesador de la máquina fue baja, y luego, en unas pocas horas, se ejecutó la nueva versión de picard, pero más usuarios agregaron tareas al host, lo que provocó una gran carga . Entonces la segunda tarea se ejecutará más lento solo por el otro tráfico. Por lo tanto, no tendría sentido cronometrarlos, porque las estadísticas no estarían en las mismas condiciones. –

+0

también, ¿por qué no p.join() en el mismo ciclo for como p.start()? –

+0

también eres un genio y te amo, funcionó. –

0

creo que algo como esto debería funcionar:

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

No sé dónde está su error iteración es cuando (qué línea es?).

Además, creo que será mejor que los ejecute por separado. Cuando los ejecuta juntos, corre el riesgo de que un proceso reciba más tiempo de CPU y parezca más rápido, incluso cuando no lo sea.