Schrift
[thread]12450[/thread]

Mehrere Prozesse für Dual/Quad Core

Leser: 1


<< >> 7 Einträge, 1 Seite
Snicker
 2008-09-05 21:24
#114305 #114305
User since
2008-08-09
25 Artikel
BenutzerIn
[default_avatar]
Hi,
möchte mit meinem Programm mehrere Prozesse gleichzeitig ausführen, in Abhängigkeit von meinen vorhanden Cores. Dafür benutze ich den fork() Befehl.
Problematisch ist, dass zwar die gewünschte Anzahl an Prozessen gestartet wird, aber leider zählt das Programm die Variable $k1 nicht richtig hoch.
So sieht es im Fenster aus:
0
0 Simulation wird berechnet $k1 = 1 q = 1
0
0 Simulation wird berechnet $k1 = 1 q = 1
.... Programm wird ausgeführt....
.... Programm wird ausgeführt....

Die Batchdatei wird nun zweimal gestartet und verursacht nun einen Fehler im Programm. Ohne den Versuch meherere Prozesse zu starten, funktioniert alles fehlerfrei.
Ich weiß nur nicht, warum Perl die Varibale $k1 falsch hochzählt und warum der Befehl "system ("$batch$test1.bat");" erst so spät startet.


Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$q = 0;
while ($q < @einstellungen_para_wert[3]){
    my $pid = fork() ;
    my $k1 = 0;
    my $cores = 2;
    my $test1;
    if (($k1 < $cores) && ($pid ==0)){
        print "$k1\n";
        open (BATCHDATEI, ">$batch$q.bat");
        print BATCHDATEI "\@echo off\n CopasiSE @einstellungen_para_wert[2]@einstellungen_para_wert[0]$q@einstellungen_para_wert[1] --save @einstellungen_para_wert[2]@einstellungen_para_wert[0]$q$random@einstellungen_para_wert[1]";
        $test1 = $q + $k1;
        $k1++;
        print "$test1 Simulation wird berechnet \$k1 = $k1 \q = $q\n";
        system ("$batch$test1.bat");
        $q++;
        $k1--;
    }
}
pq
 2008-09-05 21:49
#114306 #114306
User since
2003-08-04
12208 Artikel
Admin1
[Homepage]
user image
also was mir gleich auffällt:
du machst nicht direkt nach dem fork eine abfrage, ob du im child bist oder nicht.
der gesamte code nach dem fork wird also zweimal ausgeführt, vom parent und child.
ausserdem wird sogar die schleife vom child ausgeführt.
desweiteren erstellst du $k1 erst in der schleife, nach dem fork.
du musst sie im parent und ausserhalb der schleife setzen.
üblicherweise schreibt man ein fork so:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
my $pid = fork();
unless (defined $pid) {
    die "Could not fork $!";
}
elsif (!$pid) [
    # child
    exit;
}
else {
    # parent, inkrementiere $k1 etc.
}


zur demonstration mit der schleife:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
perl -wle'
for (1 .. 2) {print "($$) start of loop $_";
my $pid = fork;
print "($$) ($pid) loop $_";
}'
(5305) start of loop 1
(5305) (5306) loop 1
(5305) start of loop 2
(5306) (0) loop 1
(5306) start of loop 2
(5307) (0) loop 2
(5308) (0) loop 2
(5305) (5307) loop 2
(5306) (5308) loop 2


wie man sieht, wird die schleife drei mal ausgeführt, zweimal vom parent und einmal vom child.
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. -- Damian Conway in "Perl Best Practices"
lesen: Wiki:Wie frage ich & perlintro Wiki:brian's Leitfaden für jedes Perl-Problem
Gast Gast
 2008-09-05 23:09
#114307 #114307
hab mal deine Beispielschleife ausprobiert und bekomme eine etwas andere Ausgabe:
(2384) start of loop 1
(2384) (-2352) loop 1
(2384) start of loop 2
(2384) (-2028) loop 2
(-2352) (0) loop 1
(-2352) start of loop 2

zumal ich eine Fehlermeldung bekomme.

Hab den Quelltext etwas umgeschrieben. Jetzt arbeitet er die richtige Reihenfolge ab, aber leider nur einen Prozess nach dem anderem. Wie schaffe ich es dass er 2 oder mehr Prozesse zulässt?

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$q = 0;
my $k1 = 0;
my $cores = 2;
my $test1;
while ($q < @einstellungen_para_wert[3]){
    my $pid = fork() ;
    unless (defined $pid) {
        die "Could not fork $!";
    }
    elsif (!$pid){
            print "$k1\n";
            open (BATCHDATEI, ">$batch$q.bat");
            print BATCHDATEI "\@echo off\n CopasiSE @einstellungen_para_wert[2]@einstellungen_para_wert[0]$q@einstellungen_para_wert[1] --save @einstellungen_para_wert[2]@einstellungen_para_wert[0]$q$random@einstellungen_para_wert[1]";
            $test1 = $q + $k1;
            $k1++;
            print "$test1 Simulation wird berechnet \$k1 = $k1 \q = $q\n";
            system ("$batch$test1.bat");
            $q++;
            $k1--;
    }
    else{
        exit(0);
    }
}
pq
 2008-09-05 23:15
#114308 #114308
User since
2003-08-04
12208 Artikel
Admin1
[Homepage]
user image
erstens: wie schon gesagt, musst du $k1 bzw. $q im parent inkrementieren, im child bringt es nix,
da es sich nicht auf den parent-prozess auswirkt.

zweitens:
du machst das exit im parent. das heisst, in der ersten schleife steigt dein parent aus, aber das
child geht nun weiter durch die schleife. du musst das child mit exit beenden.
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. -- Damian Conway in "Perl Best Practices"
lesen: Wiki:Wie frage ich & perlintro Wiki:brian's Leitfaden für jedes Perl-Problem
Gast Gast
 2008-09-06 00:30
#114310 #114310
Hab mich jetzt eng an deine Vorlage gehalten.
Für "elsif (!$pid)" komme ich erst gar nicht in die Schleife rein, daher hab ich es umgeändert zu "elsif ($pid)".
Die gestarteten Prozesse werden auch bearbeitet, nur muss ich mir jetzt was überlegen, wie ich nur maximal $cores Prozesse startet.
Aber vielen Dank erstmal für deine Hilfe!
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$q = 0;
my $k1 = 0;
my $cores = 2;
my $test1;
while ($q < @einstellungen_para_wert[3]){
    for (1..$cores){
        my $pid = fork() ;
        unless (defined $pid) {
            die "Could not fork $!";
        }
        elsif ($pid){
            print "\t$q\n";
            open (BATCHDATEI, ">$batch$q.bat");
            print BATCHDATEI "\@echo off\n CopasiSE @einstellungen_para_wert[2]@einstellungen_para_wert[0]$q@einstellungen_para_wert[1] --save @einstellungen_para_wert[2]@einstellungen_para_wert[0]$q$random@einstellungen_para_wert[1]";
            system ("$batch$q$batchformat");
            exit (0);
        }
        else{
            print "$q Simulation wird berechnet \q = $q\n";
            $q++;
        }
    }
}
pq
 2008-09-06 02:16
#114311 #114311
User since
2003-08-04
12208 Artikel
Admin1
[Homepage]
user image
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
perl -wle'
for my $id (1 .. 10) {

my $pid = fork();
unless (defined $pid) {
die "Could not fork $!";
}
elsif (!$pid) {
sleep rand(2);
print "child $$";
exit;
}
else {
print "parent $$ forked $pid";
}
}'

evtl. musst du das !$pid in $pid < 0 oder so umwandeln unter windows.
die logik jedoch einfach umzudehen hilft nichts, du musst schon verstehen, was du da tust.
wenn windows in einem child als $pid etwas negatives liefert, dann kommen sowohl
parent als auch child in den if-block. das willst du sicher auch nicht.
mehr kann ich jetzt auch nicht mehr sagen.
erst wenn du das korrekt gelöst, kannst du über die begrenzung der gleichzeitigen
prozesse nachdenken. aber ich bin nicht sicher, ob das unter windows alles so klappt.
unter linux mit POSIX. perldoc POSIX
$pid = POSIX::waitpid( -1, POSIX::WNOHANG );
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. -- Damian Conway in "Perl Best Practices"
lesen: Wiki:Wie frage ich & perlintro Wiki:brian's Leitfaden für jedes Perl-Problem
Snicker
 2008-09-06 20:53
#114314 #114314
User since
2008-08-09
25 Artikel
BenutzerIn
[default_avatar]
Mittlerweile läuft es, auch wenn ich zur Kontrolle der Prozessanzahl einen faulen Kompromiss eingehen musste.
Die Abfrage auf Existens der Zieldatei ist keine sonderlich gut Lösung, aber sie funktioniert immerhin zuverlässig.

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$q = 0;
$k1 = 0;
while ($q < @einstellungen_para_wert[3]){
    my $pid = fork() ;
    unless (defined $pid) {
        die "Could not fork $!";
    }
    elsif ($pid < 0){
            open (BATCHDATEI, ">$batch$q$batchformat");
            print BATCHDATEI "\@echo off\n CopasiSE @einstellungen_para_wert[2]@einstellungen_para_wert[0]$q@einstellungen_para_wert[1] --save @einstellungen_para_wert[2]@einstellungen_para_wert[0]$q$random@einstellungen_para_wert[1]";
            print "$batch$q$batchformat\n";
            system ("$batch$q$batchformat");
            wait;
            exit(0);
    }
    else{
        sleep(1);
        $k1++;
        print "$k1\n";
        while ($k1 == $cores){
            for (my $op = $q; $op < ($q + $cores); $op++){
                if (-e "$modelldatei$q$random@einstellungen_para_wert[1]"){
                    $k1--;
                }
            }
            sleep(1);   #Programm pausiert 1 Sek. sonst beansprucht Perl die frei werdenen Ressourcen.
        }
        $q++;
    }
}
<< >> 7 Einträge, 1 Seite



View all threads created 2008-09-05 21:24.