我正在编写一个脚本,它从命令行
获取一系列参数script.pl start end
for ($k1=$start; $k1<$end; $k1 += 0.001) {
for ($k2=$start; $k2<$end; $k2 += 0.01) {
for ($k3=$start; $k3<$end; $k3 += 0.001) {
for ($k4=$start; $k4<$end; $k4 += 0.001) {
for ($k5=$start; $k5<$end; $k5 += 0.001) {
...
}}}}}
如果我将参数设置在0到1之间,则需要很长时间。最简单的方法是将它们分成更小的间隔,如
script.pl 0 0.01
script.pl 0.01 0.02
...
script.pl 0.9 1
然后我必须同时打开100个屏幕!!
有人可以指导我如何自动完成吗?
我不确定最好的方法是什么,因为这个原因我问道。我有256个核心。
答案 0 :(得分:2)
查看并行代码时真正关键的问题是依赖关系。我将假设 - 因为你的脚本可以细分 - 你在循环中没有做任何复杂的事情。
但是因为你踩着0.001和5个循环深度,你只是做了很多次迭代,如果你要从0变为1. 100,000,000,000,000,确切地说。
为了并行化,我个人建议您“展开”外部循环并使用Parallel::ForkManager
。
E.g。
my $CPU_count = 256;
my $fork_manager = Parallel::ForkManager->new($CPU_count);
for ( my $k1 = $start; $k1 < $end; $k1 += 0.001 ) {
# Run outer loop in parallel
my $pid = $fork_manager->start and next;
for ( my $k2 = $start; $k2 < $end; $k2 += 0.01 ) {
for ( my $k3 = $start; $k3 < $end; $k3 += 0.001 ) {
for ( my $k4 = $start; $k4 < $end; $k4 += 0.001 ) {
for ( my $k5 = $start; $k5 < $end; $k5 += 0.001 ) {
...;
}
}
}
}
$fork_manager->end;
}
这将做的是 - 对于那个'外部'循环的每次迭代,分叉你的进程并运行4个内部循环作为一个单独的进程。它将限制在256个并发进程。您应该将其与可用的CPU数量相匹配。
请记住 - 这只适用于琐碎的“cpu密集型”任务。如果您正在执行大量磁盘IO或尝试共享内存,这将无法正常工作。
另请注意 - 如果外部循环上的步数少于CPU的数量,则它将无法很好地并行化。
我还要注意 - $k2
有一个较小的迭代器。我从你的来源复制了它,但它可能是一个错字。
答案 1 :(得分:1)
我不确定你的意思但是这将在后台并行启动100个工作。请注意,它可以让您的计算机瘫痪,具体取决于您的硬件:
$ seq 0 0.02 0.99 | perl -lne 'print "$_ ",$_+0.01' |
while read start end; do script.pl $start $end; done; script.pl 0.99 1
这个想法是使用seq
来生成间隔,通过一个打印出对的perl脚本来管道。然后由bash循环读取这些内容,并使用相关参数启动脚本。
但请注意,这远非实现目标的优雅方式。您可能希望研究GNU Parallel或Perl本身可用的各种并行化工具。
答案 2 :(得分:1)
terdon答案的变体:
paste <(seq -w 0 .01 1) <(seq -w 0.01 0.01 1.01) | xargs -n2 -P 255 ./script.pl
将在下一个表单中启动255个并列进程
./script.pl 0.00 0.01
./script.pl 0.01 0.02
...
...
./script.pl 0.98 0.99
./script.pl 0.99 1.00