【问题标题】:Perl subroutine running more slowly with each successive callPerl 子例程在每次连续调用时运行得更慢
【发布时间】:2012-01-23 07:26:28
【问题描述】:

我有一个奇怪的问题,我连续多次调用同一个子例程,处理相同的数据,每次调用我的代码都会花费更长的时间。我的程序正在做一些矩阵数学,但我在这里问一个更一般的问题,看看是否有人有同样的问题,所以我不知道细节是否重要。下面是我的主程序循环最底部的代码。

use Time::HiRes qw (gettimeofday);

($lus2_sec,$lus2_usec) = gettimeofday();
@blah_LU_v2 = invert_LU_v2(@zmatrix);
($lue2_sec,$lue2_usec) = gettimeofday();
$lu2_elapsed = sprintf("%.3f", ($lue2_sec+($lue2_usec/1000000))-($lus2_sec+($lus2_usec/1000000)));
syswrite STDOUT, "$lu2_elapsed seconds\n";

($lus2_sec,$lus2_usec) = gettimeofday();
@blah_LU_v2 = invert_LU_v2(@zmatrix);
($lue2_sec,$lue2_usec) = gettimeofday();
$lu2_elapsed = sprintf("%.3f", ($lue2_sec+($lue2_usec/1000000))-($lus2_sec+($lus2_usec/1000000)));
syswrite STDOUT, "$lu2_elapsed seconds\n";

每个子例程都在相同的@zmatrix 数据上运行,它不会改变。我从每个子例程调用中得到完全相同的答案(之前已验证),所以我知道它并没有搞砸输入数据。该子例程也是一个简单的单线程结构,它在具有 96GB RAM 的空闲 12 核工作站上运行。应该没有磁盘交换或 CPU 问题,因为这台机器有足够的能力来处理这个相对较小的矩阵。然而,程序的输出结果是这样的(显然,运行了五个连续的子程序调用):

96.485 seconds
99.116 seconds
100.036 seconds
100.615 seconds
101.494 seconds

对于我运行的尽可能多的测试,子例程的速度越来越慢。如果我从命令行终止并重新启动程序,它将在 96 秒左右开始,然后每次都从那里减速。为什么会这样慢下来?

有问题的子程序如下所示。请注意,我现在使用 NYTProf 来确定调用 Math::Complex::_multiply 和 _minus 的时间增加。每次我调用 invert_LU_v2 子例程时,它都会对 Math::Complex 进行相同数量的调用,但在后续调用 invert_LU_v2 时会多花 % 的时间。也请随时批评我的代码,让我知道我做错了什么。我是初学者,没有受过培训,也不知道自己在做什么。

sub invert_LU_v2 {
    my(@junk) = (@_);
    my @matrix_local;
    my @matrix_L;
    my @matrix_B;
    my @matrix_inverse;

    my $tt;
    my $row;
    my $col;
    my $temp;
    my $reduced;
    my $normalize = 1;
    my $multiplier = 1;
    my $dimension = @junk - 1;

    for($row=1;$row<=$dimension;$row++){
        for($col=1;$col<=$dimension;$col++){
            $matrix_local[$row][$col]=$junk[$row][$col];
        }
    }

    for($row=1;$row<=$dimension;$row++){
        for($col=1;$col<=$dimension;$col++){
            if($row==$col){$matrix_L[$row][$col] = 1;$matrix_B[$row][$col] = 1;}
            else {$matrix_L[$row][$col] = 0;$matrix_B[$row][$col] = 0;}
        }
    }

    for($row=1;$row<=$dimension;$row++){

        $normalize = $matrix_local[$row][$row];
        $matrix_L[$row][$row] = $normalize;             
        for($col=1;$col<=$dimension;$col++){
            $matrix_local[$row][$col] /= $normalize;
        }

        for($temp=$row+1;$temp<=$dimension;$temp++){
            if(($temp != $row) && (abs($matrix_local[$temp][$row]) != 0)){
                $multiplier = $matrix_local[$temp][$row];
                $matrix_L[$temp][$row] = $multiplier;
                for($col=$row;$col<=$dimension;$col++){
                    $reduced = $matrix_local[$temp][$col] - $matrix_local[$row][$col]*$multiplier;
                    $matrix_local[$temp][$col] = $reduced;
                }
            }
        }
    }

    my @y_intermediate;

    for($col=1;$col<=$dimension;$col++){$y_intermediate[1][$col] = $matrix_B[1][$col]/$matrix_L[1][1]}

    for($col=1;$col<=$dimension;$col++){
        for($row=2;$row<=$dimension;$row++){
            $y_intermediate[$row][$col] = $matrix_B[$row][$col];
            for($tt=1;$tt<=($row-1);$tt++){$y_intermediate[$row][$col] -= ($matrix_L[$row][$tt]*$y_intermediate[$tt][$col])}
            $y_intermediate[$row][$col] /= $matrix_L[$row][$row];
        }
    }

    for($col=1;$col<=$dimension;$col++){$matrix_inverse[$dimension][$col] = $y_intermediate[$dimension][$col]/$matrix_local[$dimension][$dimension]}

    for($col=1;$col<=$dimension;$col++){
        for($row=($dimension-1);$row>=1;$row--){
            $matrix_inverse[$row][$col] = $y_intermediate[$row][$col];
            for($tt=($row+1);$tt<=$dimension;$tt++){$matrix_inverse[$row][$col] -= ($matrix_local[$row][$tt]*$matrix_inverse[$tt][$col])}
            $matrix_inverse[$row][$col] /= $matrix_local[$row][$row];
        }
    }

    return(@matrix_inverse);
}

【问题讨论】:

  • 有没有可能在其他地方有一个变量被填满,从而减慢了整个程序的速度?
  • 我看过了,唯一的其他变量是在其他子例程中本地定义的,或者一开始就全局定义一次,然后再也没碰过。我什至尝试在每次调用之间“取消定义”@blah_LU_v2 矩阵,但效果不佳。
  • 为什么不发布invert_LU_v2 实现?
  • 如果你没有'use strict;'和“使用警告;”在您的代码中,您为自己制造了很多麻烦。您的代码中存在内存泄漏,使用这两个 pragma 可以是检测它的第一步。
  • 我在我的代码中同时使用了严格和使用警告。两者都没有标记任何问题。

标签: perl benchmarking


【解决方案1】:

使用Benchmark 进行基准测试:-)

也许问题不在您的程序中,而是在您的测量中?

使用Devel::NYTProf 进行调试。它会向您显示很多有用的信息、时间安排等。

【讨论】:

  • NYTProf 很棒。它确实向您展示了您的时间都花在了哪里。
  • 我尝试了 Benchmark 模块,结果与我的 Time::Hires 方法中的时间相匹配。我还没有尝试过 NYTProf,但接下来我会尝试。感谢您的建议!
  • NYTProf 确实很棒。它表明子例程的每次调用都具有完全相同数量的“计算”,正如预期的那样。第二次调用时在我的子例程中花费的额外时间集中在 Math::Complex::_multiply 和 Math::Complex::_minus 中。这占时差的 95% 以上。我已将我的子问题包含在上面的主要问题中,但是其中的任何内容都会导致问题还是 Math::Complex 有问题?
  • 我认为是 Math::Complex 或者在您的代码中的某个位置,您维护了对变量的引用,并且它不会自动清除。尝试削弱你的变量,perldoc.perl.org/Scalar/Util.html
  • 第一个猜测是削弱@junk
猜你喜欢
  • 2014-01-30
  • 2020-06-27
  • 2015-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多