У меня есть параллельная автоматизация script, которая требует вызова многих других скриптов, некоторые из которых зависают, потому что они (некорректно) ждут ввода стандартного ввода или ожидают различные другие вещи, которые не произойдут. Это неважно, потому что я поймаю их alarm. Хитрость заключается в том, чтобы закрыть те, кто висел в процессе внуков, когда ребенок выключается. Я думал, что различные заклинания групп SIGCHLD
, ожидания и процесса могут сделать трюк, но все они блокируются, а внуки не получают.
Мое решение, которое работает, просто не похоже, что это правильное решение. Я пока не особо заинтересован в решении Windows, но в конце концов мне это тоже понадобится. Mine работает только для Unix, на данный момент это нормально.
Я написал небольшой script, который забирает число одновременных параллельных дочерних элементов и общее количество вилок:
$ fork_bomb <parallel jobs> <number of forks>
$ fork_bomb 8 500
В течение нескольких минут это, вероятно, повлияет на лимит процесса для каждого пользователя. Многие решения, которые я нашел, просто говорят вам увеличить лимит для каждого пользователя, но мне нужно, чтобы он работал около 300 000 раз, так что это не сработает. Точно так же предложения о повторном выполнении и т.д. Для очистки таблицы процессов не нужны мне. Я бы хотел исправить проблему, вместо того, чтобы похлопывать по ней ленту.
Я сканирую таблицу процессов, ищущую дочерние процессы, и завершаю отдельные процессы в обработчике SIGALRM
, которые должны умереть, потому что остальная часть реального кода не имеет надежды на успех после этого. Прохождение kludgey через таблицу процессов не мешает мне с точки зрения производительности, но я бы не прочь не делать этого:
use Parallel::ForkManager;
use Proc::ProcessTable;
my $pm = Parallel::ForkManager->new( $ARGV[0] );
my $alarm_sub = sub {
kill 9,
map { $_->{pid} }
grep { $_->{ppid} == $$ }
@{ Proc::ProcessTable->new->table };
die "Alarm rang for $$!\n";
};
foreach ( 0 .. $ARGV[1] )
{
print ".";
print "\n" unless $count++ % 50;
my $pid = $pm->start and next;
local $SIG{ALRM} = $alarm_sub;
eval {
alarm( 2 );
system "$^X -le '<STDIN>'"; # this will hang
alarm( 0 );
};
$pm->finish;
}
Если вы хотите завершить работу с процессами, выньте kill.
Я думал, что настройка группы процессов будет работать, чтобы я мог убить все вместе, но это блокирует:
my $alarm_sub = sub {
kill 9, -$$; # blocks here
die "Alarm rang for $$!\n";
};
foreach ( 0 .. $ARGV[1] )
{
print ".";
print "\n" unless $count++ % 50;
my $pid = $pm->start and next;
setpgrp(0, 0);
local $SIG{ALRM} = $alarm_sub;
eval {
alarm( 2 );
system "$^X -le '<STDIN>'"; # this will hang
alarm( 0 );
};
$pm->finish;
}
То же самое с POSIX setsid
тоже не работало, и я думаю, что на самом деле все пошло по-другому так как я на самом деле не осуждаю это.
Любопытно, что Parallel:: ForkManager run_on_finish
случается слишком поздно для одного и того же кода очистки: внуки, по-видимому, уже не связаны с дочерний процесс обрабатывается в этой точке.