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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
#!/usr/bin/perl use strict; use warnings; use diagnostics; use Parallel::ForkManager 1.05; if (open(my $fh,'<','config.pl')) { my $config = eval do { local $/; <$fh>; }; die "Fehler, kann Konfigurationsdatei nicht verarbeiten '$@'\n" if $@; close($fh) or die "Fehler, kann Konfigurationsdatei nicht schliessen '$!'\n"; my $forkmanager = Parallel::ForkManager->new($config->{max_prozesse}); $forkmanager->run_on_start( sub { my ($pid,$file) = @_; print "Sohn '$pid' startet mit Datei '$file'\n"; }, ); $forkmanager->run_on_finish( sub { my ($pid) = @_; print "Sohn '$pid' ist beendet\n"; }, ); $forkmanager->run_on_wait( sub { print "Warte auf Aufträge\n" }, $config->{poll_interval}, ); my $lauf = 1; while ($lauf) { if (opendir my $vh,'.') { foreach my $file ( grep { $_ =~ /^[a-z0-9]\-auftrag.dat$/ && !-z $_ } readdir $vh ) { print "Datei $file gefunden\n"; rename($file,"$file-erl"); my $pid = $forkmanager->start($file) and next; # Sohn print "Hier meldet sich Sohn '$pid' von der Front\n"; $forkmanager->finish(); } } } $forkmanager->wait_all_children; } else { die "Fehler, kann Konfigurationsdatei nicht oeffnen '$!'\n"; }
1
2
3
Datei 1-auftrag.dat gefunden
Sohn '-7568' startet mit Datei '1-auftrag.dat'
Hier meldet sich Sohn '0' von der Front
my $foo = shift $_;
2013-09-27T09:37:54 barneyEs wird in der Endlosschleife readdir() aber niemals closedir() aufgerufen. Nach Zeile 50 sollte also ein closedir $vh; eingebaut werden.
2013-09-27T09:37:54 barneyZeile 53 wird niemals erreicht. Zum Beenden des Skripts sollte ein Signal-handler eingebaut werden.
2013-09-27T09:37:54 barneyEs wirk kontinuierlich nach neuen Aufträgen gesucht. Ich würde nach Zeile 50 noch ein sleep 1; einbauen.
2013-09-27T10:49:48 GwenDragonÄhmm, auch der benutzt fork(). Was soll da stabiler werden?
2013-09-27T15:02:25 biancaHast du außer der Regex Erweiterung wirklich NICHTS geändert und es hat mit 1000 Unterprozessen geklappt??
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
#!/usr/bin/perl use strict; use warnings; use diagnostics; use Parallel::ForkManager; my $config; $config->{max_prozesse} = 1000; $config->{poll_interval} = 1; my $forkmanager = Parallel::ForkManager->new($config->{max_prozesse}); $forkmanager->run_on_start( sub { my ($pid,$file) = @_; print "Sohn '$pid' startet mit Datei '$file'\n"; }, ); $forkmanager->run_on_finish( sub { my ($pid) = @_; print "Sohn '$pid' ist beendet\n"; }, ); $forkmanager->run_on_wait( sub { print "Warte auf Aufträge\n" }, $config->{poll_interval}, ); my $lauf = 1; while ($lauf) { if (opendir my $vh,'.') { foreach my $file ( grep { $_ =~ /^[a-z0-9]+\-auftrag.dat$/ && !-z $_ } readdir $vh ) { print "Datei $file gefunden\n"; rename($file,"$file-erl"); my $pid = $forkmanager->start($file) and next; # Sohn print "Hier meldet sich Sohn '$pid' von der Front\n"; $forkmanager->finish(); } } } $forkmanager->wait_all_children;
QuoteEs benennt jedenfalls die Dateien um. Ob das so ist wie du meinst, kann ich nicht überprüfen. Teste es doch bitte mal selbst.Würde ja heißen, dass das Script logisch in Ordnung ist?
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
#!/usr/bin/perl use strict; use warnings; use diagnostics; use Parallel::ForkManager 1.05; if (open(my $fh,'<','config.pl')) { my $config = eval do { local $/; <$fh>; }; die "Fehler, kann Konfigurationsdatei nicht verarbeiten '$@'\n" if $@; close($fh) or die "Fehler, kann Konfigurationsdatei nicht schliessen '$!'\n"; my $forkmanager = Parallel::ForkManager->new($config->{max_prozesse}); $forkmanager->run_on_start( sub { my ($pid,$file) = @_; print "Sohn '$pid' startet mit Datei '$file'\n"; }, ); $forkmanager->run_on_finish( sub { my ($pid) = @_; print "Sohn '$pid' ist beendet\n"; }, ); $forkmanager->run_on_wait( sub { print "Warte auf Auftraege\n" }, $config->{poll_interval}, ); my $lauf = 1; while ($lauf) { if (opendir my $vh,$config->{data_pfad}) { foreach my $file ( grep { $_ =~ /^[a-z0-9]+\-auftrag.dat$/ && !-z $_ } readdir $vh ) { print "Datei $file gefunden\n"; rename("$config->{data_pfad}/$file","$config->{data_pfad}/$file-erl"); my $pid = $forkmanager->start($file) and next; if (!$pid) { # Sohn print "Hier meldet sich ein Sohn von der Front\n"; $forkmanager->finish(); } else { die "Fehler, kann Sohnprozess nicht starten\n"; } } } $lauf = 0 if -f "$config->{data_pfad}/stop.dat"; } $forkmanager->wait_all_children; } else { die "Fehler, kann Konfigurationsdatei nicht oeffnen '$!'\n"; }
1 2 3 4 5 6 7 8
# # Config # { 'max_prozesse' => 5, # max. Prozesse gleichzeitig 'poll_interval' => 1, # Wartezeit zwischen Läufen 'data_pfad' => '.', # Pfad für die Auftragsdateien }
1
2
3
Datei 1-auftrag.dat gefunden
Sohn '-5820' startet mit Datei '1-auftrag.dat'
Hier meldet sich ein Sohn von der Front
QuoteIf $period is defined, then $code is called periodically and the module waits for $period seconds between the two calls.
QuoteYou can define a subroutine which is called when a child is terminated. It is called in the parent process.
QuoteThe "and next" skips the internal loop in the parent process.
2013-09-27T18:38:41 biancaFrage 1: Ich hätte erwartet, dass die Ausgabe "Warte auf Auftraege" eigentlich jede Sekunde kommt, denn $config->{poll_interval} steht auf 1 und die Methode run_on_wait() verstehe ich als Anweisung für das Warten auf Kinder. Wo liegt mein Denkfehler?
QuoteIf $period is defined, then $code is called periodically and the module waits for $period seconds between the two calls.
QuoteYou can define a subroutine which is called when the child process needs to wait for the startup
QuoteFrage 2: Warum kommt die Ausgabe "Sohn '-3072' ist beendet" erst nach Ende des gesamten Programms? Der Sohn macht doch außer einem print nichts und müsste doch sofort nach seinem Start terminieren. Wo liegt hier der Fehler?QuoteYou can define a subroutine which is called when a child is terminated. It is called in the parent process.
QuoteFrage 3: Aus der Doku verstehe ich diesen Satz nicht:
QuoteThe "and next" skips the internal loop in the parent process.
Mein Script verhält sich nicht anders, wenn ich "and next" weg lasse. Warum?
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
#!/usr/bin/perl use strict; use warnings; use diagnostics; use Parallel::ForkManager 1.05; if (open(my $fh,'<','config.pl')) { my $config = eval do { local $/; <$fh>; }; die "Fehler, kann Konfigurationsdatei nicht verarbeiten '$@'\n" if $@; close($fh) or die "Fehler, kann Konfigurationsdatei nicht schliessen '$!'\n"; my $forkmanager = Parallel::ForkManager->new($config->{max_prozesse}); $forkmanager->run_on_start( sub { my ($pid,$file) = @_; print "Sohn '$pid' startet mit Datei '$file'\n"; }, ); $forkmanager->run_on_finish( sub { my ($pid) = @_; print "Sohn '$pid' ist beendet\n"; }, ); # $forkmanager->run_on_wait( # sub { # print "Naechster Prozess muss warten wegen max. Anzahl '$config->{max_prozesse}'\n" # }, # $config->{poll_interval}, # ); my $lauf = 1; while ($lauf) { print "Warte auf Auftraege\n"; if (opendir my $vh,$config->{data_pfad}) { foreach my $file ( grep { $_ =~ /^[a-z0-9]+\-auftrag.dat$/ && !-z $_ } readdir $vh ) { print "Datei $file gefunden\n"; rename("$config->{data_pfad}/$file","$config->{data_pfad}/$file-erl"); my $pid = $forkmanager->start($file) and next; if (!$pid) { # Sohn print "Hier meldet sich ein Sohn von der Front\n"; sleep(20); $forkmanager->finish(); } else { die "Fehler, kann Sohnprozess nicht starten\n"; } } } sleep($config->{poll_interval}); $lauf = 0 if -f "$config->{data_pfad}/stop.dat"; } $forkmanager->wait_all_children; } else { die "Fehler, kann Konfigurationsdatei nicht oeffnen '$!'\n"; }
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
>>hier habe ich die 1-auftrag.dat erzeugt<<
Datei 1-auftrag.dat gefunden
Sohn '-1708' startet mit Datei '1-auftrag.dat'
Hier meldet sich ein Sohn von der Front
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
>>hier wären 20 Sekunden rum <<
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
Warte auf Auftraege
>>hier habe ich die stop.dat erzeugt<<
Sohn '-1708' ist beendet
2013-09-28T05:53:58 biancaIrgendwas stimmt hier noch nicht ganz.
Warum terminiert der Sohn nicht nach 20 Sekunden sondern erst ganz am Ende?
Liegt das auch an der doofen Prozessverwaltung von Windows?
GwenDragon: Wie lief das bei deinen Tests? Sind da die Sohnprozesse auch erst ganz am Ende alle zusammen beendet worden?
raubtierrun_on_finish nimmt einen Parameter, nämlich die PID des Kindes...
Oder eben nix/0 für den Elternprozess.
2013-09-27T22:26:32 Raubtierrun_on_finish nimmt einen Parameter, nämlich die PID des Kindes...
Oder eben nix/0 für den Elternprozess.
2013-09-28T07:04:08 RaubtierDu musst halt 1x pro Kind das run_on_finish aufrufen und jeweils die pid des Kindes mitgeben.
$forkmanager->wait_one_child(WNOHANG);
2013-09-28T07:24:55 RaubtierDu musst also in deiner Haupt-Loop schreiben:
QuoteBareword "WNOHANG" not allowed while "strict subs" in use at test_daemon.pl line 61.
2013-09-28T07:04:08 RaubtierIch glaube, ich müsste es doch mal ausprobieren :-)
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
#!/usr/bin/perl require 5.016_003; use strict; use warnings; use diagnostics; use Parallel::ForkManager 1.05; use POSIX 1.30 qw(WNOHANG); use IPC::Run 0.92 qw(start pump finish timeout harness); if (open(my $fh,'<','config.pl')) { my $config = eval do { local $/; <$fh>; }; die "Fehler, kann Konfigurationsdatei nicht verarbeiten '$@'\n" if $@; close($fh) or die "Fehler, kann Konfigurationsdatei nicht schliessen '$!'\n"; my $forkmanager = Parallel::ForkManager->new($config->{max_prozesse}); $forkmanager->run_on_start( sub { my ($pid,$file) = @_; print "Sohn '$pid' startet mit Datei '$file'\n"; }, ); $forkmanager->run_on_finish( sub { my ($pid) = @_; print "Sohn '$pid' ist beendet\n"; }, ); my $lauf = 1; while ($lauf) { print "Warte auf Auftraege\n"; if (opendir my $vh,$config->{data_pfad}) { foreach my $file ( sort {(stat("$config->{data_pfad}/$a"))[9] <=> (stat("$config->{data_pfad}/$b"))[9]} grep { $_ =~ /^[a-z0-9]+\-auftrag.dat$/ && !-z $_ } readdir $vh ) { print "Datei $file gefunden\n"; rename("$config->{data_pfad}/$file","$config->{data_pfad}/$file-erl"); my $pid = $forkmanager->start($file) and next; if (!$pid) { # Sohn print "Hier meldet sich ein Sohn von der Front\n"; my ($in,$out,$err); my @prog = qw(gpg2 -h); my $handle = start(\@prog,\$in,\$out,\$err,10); pump $handle until length $out; sleep(1); $forkmanager->finish($pid); } else { die "Fehler, kann Sohnprozess nicht starten\n"; } } } $forkmanager->wait_one_child(WNOHANG); # sonst klappt das run_on_finish() nicht zeitnah sleep($config->{poll_interval}); $lauf = 0 if -f "$config->{data_pfad}/stop.dat"; } $forkmanager->wait_all_children; } else { die "Fehler, kann Konfigurationsdatei nicht oeffnen '$!'\n"; }
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
Warte auf Auftraege
Datei 1-auftrag.dat gefunden
Sohn '-4652' startet mit Datei '1-auftrag.dat'
Datei 2-auftrag.dat gefunden
Hier meldet sich ein Sohn von der Front
Sohn '-2824' startet mit Datei '2-auftrag.dat'
Datei 3-auftrag.dat gefunden
Hier meldet sich ein Sohn von der Front
Sohn '-512' startet mit Datei '3-auftrag.dat'
Datei 4-auftrag.dat gefunden
Hier meldet sich ein Sohn von der Front
Sohn '-1200' startet mit Datei '4-auftrag.dat'
Datei 5-auftrag.dat gefunden
Hier meldet sich ein Sohn von der Front
Sohn '-5700' startet mit Datei '5-auftrag.dat'
Datei 6-auftrag.dat gefunden
Hier meldet sich ein Sohn von der Front
Sohn '-4652' ist beendet
Sohn '-4768' startet mit Datei '6-auftrag.dat'
Datei 7-auftrag.dat gefunden
Hier meldet sich ein Sohn von der Front
Sohn '-1200' ist beendet
Sohn '-3684' startet mit Datei '7-auftrag.dat'
Datei 8-auftrag.dat gefunden
Hier meldet sich ein Sohn von der Front
Uncaught exception from user code:
process ended prematurely at test_daemon.pl line 59.
IPC::Run::pump('IPC::Run=HASH(0x322c814)') called at test_daemon.pl line 59
Sohn '-2824' ist beendet
Sohn '-512' ist beendet
Sohn '-5428' startet mit Datei '8-auftrag.dat'
Datei 9-auftrag.dat gefunden
Hier meldet sich ein Sohn von der Front
Sohn '-2236' startet mit Datei '9-auftrag.dat'
Datei 10-auftrag.dat gefunden
Hier meldet sich ein Sohn von der Front
Sohn '-5700' ist beendet
Sohn '-4768' ist beendet
Sohn '-2128' startet mit Datei '10-auftrag.dat'
Datei 11-auftrag.dat gefunden
Hier meldet sich ein Sohn von der Front
Sohn '-3684' ist beendet
Sohn '-5156' startet mit Datei '11-auftrag.dat'
Datei 12-auftrag.dat gefunden
Hier meldet sich ein Sohn von der Front
Sohn '-3620' startet mit Datei '12-auftrag.dat'
Sohn '-5428' ist beendet
Hier meldet sich ein Sohn von der Front
Warte auf Auftraege
Datei 13-auftrag.dat gefunden
Sohn '-2236' ist beendet
Sohn '-5860' startet mit Datei '13-auftrag.dat'
1 2 3 4 5 6 7 8
# # Config # { 'max_prozesse' => 5, # max. Prozesse gleichzeitig 'poll_interval' => 1, # Wartezeit zwischen Läufen 'data_pfad' => '.', # Pfad für die Auftragsdateien }
2013-09-28T11:04:03 pqdas ist aber auch irgendwie ein bisschen rückständig, dass du nur söhne an die front schickst...
2013-09-28T17:17:38 GwenDragonHängt irgendwann.
2013-09-28T17:17:38 GwenDragonHängt irgendwann.
QuoteIf pump() is called after all harnessed activities have completed, a "process ended prematurely" exception to be thrown. This allows for simple scripting of external applications without having to add lots of error handling code at each step of the script: