2009-12-25 16 views
15

Sono uno studente di ingegneria aerospaziale e sto lavorando a un progetto di capstone senior. Uno dei modelli matematici che sto sviluppando richiede una quantità astronomica di dati generati da XFOIL, un popolare strumento aerospaziale utilizzato per trovare i coefficienti di portanza e resistenza sui profili aerodinamici. (Ma sto divagando.)Come posso fare in modo che il mio script Perl usi più core per i processi figli?

Tagliare all'inseguimento: Ho uno script Perl che richiama ripetutamente XFOIL con diversi parametri di input per generare i dati di cui ho bisogno. Ho bisogno di XFOIL per eseguire 5600 volte, e così com'è ora ci vogliono circa 100 secondi in media per corsa. Facendo i conti, questo significa che ci vorranno circa 6,5 ​​giorni per completare.

Ora, ho una macchina quad-core, ma la mia esperienza come programmatore è limitata, e so solo come usare il Perl di base. Mi piacerebbe eseguire 4 istanze di XFOIL alla volta, tutte sul proprio nucleo. Qualcosa di simile a questo:

while (1){ 
    for (i = 1..4){ 
     if (! exists XFOIL_instance(i)){ 
      start_new_XFOIL_instance(i, input_parameter_list); 
     } 
    } 
} 

Così il programma sta controllando (o, preferibilmente, dormire fino un'istanza Xfoil la sveglia per iniziare una nuova istanza) se ogni nucleo è in esecuzione XFoil. Altrimenti, l'istanza precedente è stata chiusa e possiamo avviare una nuova istanza con la nuova lista di parametri di input.

Se qualcuno ha qualche idea di come questo possa essere raggiunto, per favore fatemelo sapere. Ciò velocizzerebbe significativamente il tempo necessario per generare dati e mi consentirà di lavorare sul progetto aerospaziale stesso.

Grazie per l'aiuto!

+1

Ho paura che non ho intenzione di fornire una risposta completa, ma la versione corta è che puoi sicuramente sborsare quattro istanze dell'attuale script perl, quindi ognuna di esse è costantemente distribuita per eseguire uno script XFOIL. Tuttavia, impostando l'affinità del processore per i processi risultanti, è necessario conoscere il sistema operativo che si sta utilizzando. –

+2

Sei sicuro che XFOIL non usi thread o altrimenti usi più processori per ottenere il tempo di esecuzione a circa 100 secondi? – dlamblin

+0

Sarebbe difficile implementare XFOIL in C/Fortran? Se no, allora ti suggerirei di provarci. Perl non è esattamente il Speedy Gonzalez dei linguaggi di programmazione ... – Zaid

risposta

17

Prova Parallel::ForkManager. È un modulo che fornisce un'interfaccia semplice per la forking di processi come questo.

Ecco qualche esempio di codice:

#!/usr/bin/perl 

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

my @input_parameter_list = 
    map { join '_', ('param', $_) } 
    (1 .. 15); 

my $n_processes = 4; 
my $pm = Parallel::ForkManager->new($n_processes); 
for my $i (1 .. $n_processes) { 
    $pm->start and next; 

    my $count = 0; 
    foreach my $param_set (@input_parameter_list) {   
     $count++; 
     if (($count % $i) == 0) { 
      if (!output_exists($param_set)) { 
       start_new_XFOIL_instance($param_set); 
      } 
     } 
    } 

    $pm->finish; 
} 
$pm->wait_all_children; 

sub output_exists { 
    my $param_set = shift; 
    return (-f "$param_set.out"); 
} 

sub start_new_XFOIL_instance { 
    my $param_set = shift; 
    print "starting XFOIL instance with parameters $param_set!\n"; 
    sleep(5); 
    touch("$param_set.out"); 
    print "finished run with parameters $param_set!\n"; 
} 

sub touch { 
    my $fn = shift; 
    open FILE, ">$fn" or die $!; 
    close FILE or die $!; 
} 

Sarà necessario fornire il proprio implementazioni per la start_new_XFOIL_instance e le funzioni output_exists, e si potrà anche definire i propri set di parametri da passare XFoil .

+1

Questo sembra essere quello di cui ho bisogno. Leggerò su Parallel :: ForkManager e ti dirò come va. Grazie per l'aiuto! Ovviamente, qualsiasi altro input da parte di chiunque altro è apprezzato. –

+0

Se non lo sapevi già, puoi installare il modulo Parallel :: ForkManager nella tua home directory. Guarda qui per sapere come fare: http://stackoverflow.com/questions/540640/how-can-i-install-a-campo-module-into-a-local-directory –

+1

James, grazie mille per il tuo Aiuto. Ho installato Parallel :: ForkManager tramite la riga di comando un po 'di tempo fa - Penso di essere attivo e funzionante ora. Sto ancora cercando di capire le complessità del modulo e come voglio che si comporti in condizioni di errore, ma una corsa preliminare sul mio portatile dual-core mi porta a pensare che l'ho capito - almeno il idea di base, comunque. Grazie ancora! –

3

Sembra che si possa usare gearman per questo progetto.

www.gearman.org

Gearman è una coda di lavoro. Puoi dividere il tuo flusso di lavoro in un sacco di mini parti.

Suggerirei di utilizzare amazon.com o anche i loro server in grado di completare questo progetto.

La spesa di 10 centesimi per ora di calcolo o meno, può spead significativamente il vostro progetto.

Vorrei usare gearman localmente, assicurati di avere una corsa "perfetta" per 5-10 dei tuoi subjobs prima di portarla in una fattoria di calcolo amazzonica.

3

Perl threads sfrutterà più core e processori. Il principale pro di thread è abbastanza facile condividere i dati tra i thread e coordinare le loro attività. Un processo biforcato non può facilmente restituire dati al genitore né coordinarsi tra loro.

I problemi principali dei thread Perl sono relativamente costosi da creare rispetto a un fork, devono copiare l'intero programma e tutti i relativi dati; devi averli compilati nel tuo Perl; e possono essere bacati, il più vecchio il Perl, il buggiere i fili. Se il tuo lavoro è costoso, il tempo di creazione non dovrebbe avere importanza.

Ecco un esempio di come potresti farlo con i thread. Ci sono molti modi per farlo, questo usa Thread::Queue per creare un grande elenco di lavori che i thread dei lavoratori possono condividere. Quando la coda è vuota, i thread escono. I principali vantaggi sono che è più facile controllare quanti thread sono attivi e non è necessario creare un nuovo thread costoso per ogni bit di lavoro.

Questo esempio sposta tutto il lavoro in coda contemporaneamente, ma non c'è motivo per cui non si possa aggiungere alla coda mentre si va. Se lo facessi, dovresti usare dequeue invece di dequeue_nb che aspetteranno altri input.

use strict; 
use warnings; 

use threads; 
use Thread::Queue; 

# Dummy work routine 
sub start_XFOIL_instance { 
    my $arg = shift; 
    print "$arg\n"; 
    sleep 1; 
} 

# Read in dummy data 
my @xfoil_args = <DATA>; 
chomp @xfoil_args; 

# Create a queue to push work onto and the threads to pull work from 
# Populate it with all the data up front so threads can finish when 
# the queue is exhausted. Makes things simpler. 
# See https://rt.cpan.org/Ticket/Display.html?id=79733 
my $queue = Thread::Queue->new(@xfoil_args); 

# Create a bunch of threads to do the work 
my @threads; 
for(1..4) { 
    push @threads, threads->create(sub { 
     # Pull work from the queue, don't wait if its empty 
     while(my $xfoil_args = $queue->dequeue_nb) { 
      # Do the work 
      start_XFOIL_instance($xfoil_args); 
     } 

     # Yell when the thread is done 
     print "Queue empty\n"; 
    }); 
} 

# Wait for threads to finish 
$_->join for @threads; 

__DATA__ 
blah 
foo 
bar 
baz 
biff 
whatever 
up 
down 
left 
right 
+0

Vedo che il mio commento precedente (o la tua precedente risposta) è stato cancellato, comunque grazie per aver aggiornato la tua risposta. Sono curioso di sapere se i thread possono trarre vantaggio da più core e processori, in caso affermativo, come l'hai verificato? = =) – user454322

+0

@ user454322 Dopo aver visto il tuo commento, ho scritto un piccolo script per fare un ciclo infinito in un mucchio di thread e ho usato Activity Monitor su OS X per vedere che tutti e quattro i core erano in uso.Hai ragione sul fatto che il modello di threading sia un nuovo interprete Perl per thread reale. Precedentemente mi ero messo in testa che era tutto emulato in un unico processo. – Schwern

+0

Ho pubblicato http://stackoverflow.com/questions/12536064/how-does-perls-threading-system-work, se ne avete la possibilità, per favore date un'occhiata. – user454322

0

Avete pensato a gnu parallel parallel. Ti consentirà di eseguire diverse istanze di installazione del tuo programma con diversi input e riempirà i core della CPU man mano che iniziano a essere disponibili. Spesso è un modo molto semplice ed efficace per raggiungere la parallelizzazione di compiti semplici.

0

Questo è piuttosto vecchio, ma se qualcuno è ancora alla ricerca di risposte adeguate a questa domanda, si potrebbe prendere in considerazione Perl Many-Core-Engine (MCE)

Problemi correlati