2010-12-13 22 views
6

Hola Tengo un script simple que toma un archivo y ejecuta otro script Perl en él. La secuencia de comandos hace esto a cada archivo de imagen en la carpeta actual. Esto se ejecuta en una máquina con 2 procesadores Xeon de cuatro núcleos, 16 gb de ram, ejecutando RedHat Linux.¿Cómo puedo modificar mi script Perl para usar múltiples procesadores?

El primer script work.pl básicamente llama a magicplate.pl pasa algunos parámetros y el nombre del archivo para magicplate.pl para procesar. La placa mágica tarda aproximadamente un minuto en procesar cada imagen. Debido a que work.pl está realizando la misma función más de 100 veces y porque el sistema tiene múltiples procesadores y núcleos, estaba pensando en dividir la tarea para que pueda ejecutarse varias veces en paralelo. Podría dividir las imágenes en diferentes carpetas si es necesario. Cualquier ayuda sería genial. Gracias

Esto es lo que tengo hasta ahora:

use strict; 
use warnings; 


my @initialImages = <*>; 

foreach my $file (@initialImages) { 

    if($file =~ /.png/){ 
     print "processing $file...\n"; 
     my @tmp=split(/\./,$file); 
     my $name=""; 
     for(my $i=0;$i<(@tmp-1);$i++) { 
      if($name eq "") { $name = $tmp[$i]; } else { $name=$name.".".$tmp[$i];} 
     } 

     my $exten=$tmp[(@tmp-1)]; 
     my $orig=$name.".".$exten; 

     system("perl magicPlate.pl -i ".$orig." -min 4 -max 160 -d 1"); 
    } 
}  

Respuesta

3

Usted podría utilizar en paralelo :: ForkManager (conjunto $ MAX_PROCESSES al número de archivos procesados ​​al mismo tiempo):

use Parallel::ForkManager; 
use strict; 
use warnings; 

my @initialImages = <*>; 

foreach my $file (@initialImages) { 

    if($file =~ /.png/){ 
     print "processing $file...\n"; 
     my @tmp=split(/\./,$file); 
     my $name=""; 
     for(my $i=0;$i<(@tmp-1);$i++) { 
      if($name eq "") { $name = $tmp[$i]; } else { $name=$name.".".$tmp[$i];} 
     } 

     my $exten=$tmp[(@tmp-1)]; 
     my $orig=$name.".".$exten; 

    $pm = new Parallel::ForkManager($MAX_PROCESSES); 
    my $pid = $pm->start and next; 
     system("perl magicPlate.pl -i ".$orig." -min 4 -max 160 -d 1"); 
    $pm->finish; # Terminates the child process 

    } 
}  

Pero como sugiere Hugmeir corriendo intérprete de Perl y otra vez para cada nuevo archivo no es una buena idea

+2

"ejecutar intérprete perl una y otra vez para cada archivo nuevo no es una buena idea" - Sí, pero cuando se bifurca, no está iniciando un nuevo intérprete perl. Fork copia el proceso principal y Linux usa CoW, por lo que es incluso más económico que una copia completa. – JimB

+2

Además, ¿por qué está comenzando un nuevo intérprete después de la bifurcación? Ejecute el código perl en el nuevo proceso hijo. – JimB

+0

@JimB: me refiero a la llamada al sistema no bifurcada. Y uso la llamada al sistema porque el código original lo usaba. – gangabass

7

Necesitamos tomar en consideración la creación de un nuevo proceso para cada archivo que desea procesar - Es terriblemente ineficiente, y probablemente lo que está tomando la mayor parte de tu tiempo aquí. Solo cargar Perl y los módulos que uses una y otra vez deberían estar creando una sobrecarga. Recuerdo un cartel en PerlMonks que hizo algo similar, y terminó transformando su segundo script en un módulo, reduciendo el tiempo de trabajo de una hora a un par de minutos. No es que deba esperar una mejora tan dramática, pero uno puede soñar ...

Con la segunda secuencia de comandos refactorizada como un módulo, here's an example of thread usage, en la que BrowserUK crea un grupo de subprocesos, alimentando los trabajos a través de una cola.

+5

Iniciar un nuevo intérprete de Perl es terriblemente ineficiente, pero crear un nuevo proceso con fork() es muy rápido (especialmente desde que Linux usa CoW). – JimB

+2

No. Si su trabajo va a usar 1 minuto de tiempo de CPU, el tiempo invertido en comenzar la nueva tarea será bastante insignificante.Perl podría usar, digamos, 1 segundo de CPU para iniciar su entorno (si tiene muchos módulos cargados, lo he visto) pero después de eso, es todo suyo. Lea la pregunta cuidadosamente. – MarkR

+1

NB: los hilos Perl apestan. Realmente, lo hacen. Crean cargas de copias de todo (no copias de CoW, copias reales). No funcionan bien en algunos casos, pero aún consumen montones de recursos innecesarios. En cambio, Fork es mucho más eficiente y más probable que funcione. – MarkR

3
  • Importe "maigcplate" y use threading.
  • inicio magicplate.pl en el fondo (que tendría que añadir la limitación de procesos)
  • importación "magicplate" y el uso de tenedor (añadir la limitación de procesos y una segadora kiddy)
  • Marca "maigcplate" un demonio con una piscina de los trabajadores = # de CPUs
    • utilizar una aplicación MQ para la comunicación
    • tomas de uso para la comunicación
  • uso del servidor web (nginx, Apache, ...) y envolver en REST para un servicio web
  • etc ...

Todos éstos se centran en la creación de varios trabajadores que pueda cada corrida en su propia CPU. Ciertas implementaciones utilizarán mejor los recursos (aquellos que no inician un nuevo proceso) y serán más fáciles de implementar y mantener.

Cuestiones relacionadas