每次连续调用 Perl 子例程运行速度都会变慢

发布于 2024-12-28 13:25:52 字数 3929 浏览 0 评论 0原文

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

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);
}

I have a strange problem where I call the same subroutine several times in succession, processing the same data, and my code takes successively longer with each call. My program is doing some matrix mathematics, but I am asking a more general question here to see if anyone has the same issue, so I don't know if the specifics are important. Below is code at the very bottom of my main program loop.

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";

Each subroutine operates on the same @zmatrix data, which it does not change. I get the exact same answer from each subroutine call (verified earlier), so I know it's not screwing up the input data. The subroutine is also a simple single threaded structure, and this is being run on an idle 12-core workstation with 96GB of RAM. There should be no disk swapping or CPU issue since this machine has more than enough power to handle this relatively small matrix. However, the output of the program results in something like this (running five successive calls of the subroutine, obviously):

96.485 seconds
99.116 seconds
100.036 seconds
100.615 seconds
101.494 seconds

The subroutine keeps getting a little slower for as many tests as I've run. If I terminate and relaunch the program from the command line, it will start out at around 96 seconds and then slow down from there every single time. Why would it be slowing down like this?

The subroutine with the issue is shown below. Note that I've now used NYTProf to nail down the time increase to calls of Math::Complex::_multiply and _minus. Each time I call the invert_LU_v2 subroutine, it makes the same number of calls to Math::Complex, but they take a few % longer on subsequent calls of invert_LU_v2. Please also feel free to critique my code and let me know what else I'm doing wrong. I am a beginner, have no training, and don't really know what I'm doing.

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);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

时光病人 2025-01-04 13:25:52

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

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

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

Use Benchmark to do benchmarks :-)

Maybe the problem not in your program but in your measurment?

Use Devel::NYTProf for debug. It will show you a lot of useful info, timings, etc.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文