所以我有一个perl脚本,可以在那里找到一些流(我不知道有多少件是预先存在的)
但我无法想出一个知道什么时候停止wget&#f ing的好方法。现在如果wget返回不成功,我们创建一个名为" end"一旦主程序看到它,它就会停止循环。有没有更好的方法来做这件事?
显然,如果顺序完成而不是同时完成会很容易,但我试图让它下载速度最快。
my $link = $ARGV[0];
my ($url) = $link=~ m/(.+-)\d+.ts/i;
my $num = 0;
#while the file END doesn't exist
my @pids;
while (! -e "END") {
#create the URL, increment by 1
my $video=$url.++$num.".ts";
die "could not fork" unless defined (my $pid = fork());
#child process goes until wget returns invalid, create END
if (not $pid) {
system ("wget -T 5 -t 5 $video");
`touch END` if $? != 0;
exit;
}
push @pids, $pid;
}
#parent process still running, waiting for the same END file.
for my $pid (@pids) { waitpid $pid,0; }
print "pids finished\n";
sleep 1;
`rm END`;
答案 0 :(得分:3)
您没有指出可能有多少进程,但没有资源是无限制的,您应该限制数量,否则当达到饱和时您会看到性能快速下降。
在外出网络时更是如此,因为你可能会烦恼服务器(事情也会很快停止加速)。也许一次可以运行几十个进程?
然后一个选项是使用Parallel::ForkManager限制多个并行下载。它有return data to parent的方式,所以孩子可以报告失败。然后它的run_on_finish
方法可以检查每个批次是否有这样的标志(失败),并设置一个控制分叉的变量。
use warnings;
use strict;
use Parallel::ForkManager;
my $pm = Parallel::ForkManager->new(2); # only 2 for a managable demo
my $stop_forking;
# The sub gets 6 parameters, but only first (pid) is always defined
# The last one is what a child process may have passed
$pm->run_on_finish(
sub { $stop_forking = 1 if defined $_[-1] }
);
for my $i (0..9)
{
last if $stop_forking;
$pm->start and next; # forks
my $ret = run_job($i); # child process
# Pass data to parent under a condition
if ($ret eq 'FAIL') { $pm->finish(0, \$ret) } # child exits
else { $pm->finish }
}
$pm->wait_all_children;
sub run_job {
my ($i) = $_[0];
sleep 2;
print "Child: job $i exiting\n";
return ($i == 3 ? 'FAIL' : 1);
}
这会在$i == 3
的一批作业之后停止分叉。添加用于诊断的打印件。
“回调”run_on_finish
仅在整批完成时运行。 * 其中的匿名子总是收到6个参数,但只有第一个,孩子的pid,总是被定义。最后一个数据可能由孩子传递,当发生这种情况时,我们设置标志。子项可以通过将标量引用传递给finish
方法来返回数据。为了表明条件我们可以简单地传递任何东西。我使用\$ret
作为传递实际数据的示例。
有关详细信息,请参阅文档,但这可以满足您的需求。
如果你想像你一样分叉,我首先会在那里放一点sleep
,所以你不要用太多的请求轰炸服务器。您的孩子可以使用socketpair与父母交谈。失败的孩子可以写,而其他人只能关闭他们的插座。父母一直在检查,例如来自IO::Select的can_read
。 perlipc中有一个例子。由于您只需要孩子写信给父母,pipe就足够了。
您也可以使用信号进行操作。失败的孩子将(例如)SIGUSR1
发送给父母,父母将其捕获并设置一个控制更多分叉的全局变量。这更简单,因为父母只捕获一个信号,而不关心它来自何处。请参阅perlipc和sigtrap pragma。
你也可以使用一个文件,就像你一样,这可能是最简单的,因为在这里你不关心赛车问题(儿童是否写重叠),而只关注一个空文件出现。
但是,在所有这些中,您还希望限制并行进程的数量。
最后,有许多模块可以帮助解决这个问题,例如IPC::Run。
* 要在每个子项退出时使用reap_finished_children运行回调权限。请参阅this post。