使用Perl脚本以最佳方式利用可用的CPU

3
我写了一个小的Perl脚本,使用for循环以不同参数多次启动程序。该程序进行数字计算,如果可以获得整个CPU,则使用整个CPU。我有几个可用的CPU,因此理想情况下,我希望一次启动与可用CPU数量相同的程序实例,但不要超过可用CPU数量。由于可能有其他进程正在运行,可用CPU数量并不总是相同。
到目前为止我所做的是:
#!/usr/bin/perl

use strict;
use warnings;

use IPC::Open2;
use Parallel::ForkManager;

my $program = "./program";

my($out, $in);
my $pid;

my $pm = new Parallel::ForkManager(44);

for my $x (0..100){
          my $childpid = $pm->start and next; 
          $pid= open2($out, $in, $program);

          print $in <<EOF;
          #input involving $x
EOF
          my $printstring = "";
          while(<$out>){
            if (/^\s*1\.000\s+(-\S+)D(\S+)\s*$/){
               $printstring .= "$1e$2";
            }
          }
          print $printstring, "\n";
          waitpid( $pid, 0 );
          $pm->finish;

}
$pm->wait_all_children;
print "\n\n END\n";

这显然包含了启动的固定进程数量,因此可以使用固定数量的CPU,我不知道如何改变它以灵活确定可用的CPU并相应地更改子进程的数量。有什么想法吗?

更新:

只是为了明确起见,限制因素肯定是CPU时间而不是I/O问题。

我研究了loadavg,但我对其输出感到困惑。

68.71 66.40 63.72 70/1106 19247

同时,top显示

Tasks: 978 total,  23 running, 955 sleeping,   0 stopped,   0 zombie
Cpu(s):  2.1%us,  1.5%sy, 93.3%ni,  3.1%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

该系统有48个CPU。因此,我本以为如果第四个数字(在本例中为70)大于48,就不应再启动任何子进程。然而,根据top命令的显示情况,似乎还有一些空闲的CPU,尽管第四个数字是70。


启动正确数量的进程取决于所涉及的任务类型(内存密集型?CPU绑定?I/O密集型?)。查看/proc/cpuinfo以查看您安装了什么。 - xxfelixxx
http://search.cpan.org/~jstowe/Linux-Cpuinfo-1.10/lib/Linux/Cpuinfo.pm - xxfelixxx
@xxfelixxx 如果你允许程序一次运行占用100%的CPU。 - fifaltra
@xxfelixxx 我知道我有哪些CPU,不需要脚本来确定硬件信息。我有48个可用的CPU,这就是为什么我将最大子进程数设置为44的原因,这样可以留出一些CPU供其他想要计算某些东西的人使用。我宁愿找出目前有多少空闲的CPU,并相应地调整子进程数。 - fifaltra
@fifaltra,请检查 loadavg。简单来说,它告诉你现在有多少个 CPU/核心正在使用。如果这个数字大于 CPU 的数量,那么系统就超载了。 - Dummy00001
显示剩余7条评论
2个回答

2
我建议采取稍微不同的方法-不是基于负载“限制”活动进程数,而是使用 SIGSTOPSIGCONTParallel::ForkManager 提供了一个 running_procs 方法,该方法返回 PID 列表。然后,当负载平均值变得“过高”时,可以向这些进程发送 STOP 信号。您可以使用 Sys::Info::CPU 找到“过高”,同时也会告诉您 load,或者 - 可以查看命令行中的处理器/核心数。但是,概念上,当负载过高时,向某些子进程发出 'SIGSTOP'。它们应该从运行队列中退出,并处于可见但挂起状态。关于负载平均值-您会得到3个数字。1m、5m和15m的 CPU 负载。查看第一个数字,如果大于 CPU 数量,则有争用。

1

可能会有一些进程在运行,其中一些会使用更多的CPU。我认为另一种方法是查看每个CPU使用其空闲百分比的忙碌程度。以下代码片段可以实现这个目标。然后您可以设置一个阈值来确定它是否超过了某个空闲量。您可以使用返回的数字来基于启动多少进程的逻辑。像这样的东西应该会有所帮助:

#!/usr/bin/env perl

use strict;
use warnings;
use FileHandle;

#Get number of cores over 95% idle
# this can be adjusted
my $idle_percent=90;
my $free_cores=GetCores($idle_percent);
printf( "Cores over %s free: %s\n",$idle_percent,$free_cores);

sub GetCores {
    my $threshold=shift;
    my $cpu_idle_count=0;

    my $delta_time_sleep=2; #Amount of sleep between the 2 samples
    my @cpu_idle_totals;
    my @cpu_total_totals;

    for(0..1) {
        my $output_fh=FileHandle->new('/proc/stat','r') or die "No stat";
        # Get output of /proc/stat
        while ( my $line=$output_fh->getline() ) {
            chomp($line);
            my ($tag,$user,$nice,$system,$idle,$iowait,$irq,$softirq)
                =split( /\s+/, $line);

            if ( $tag=~ m/cpu(.+)/ ) {
                my $cpu_number=$1;

                my $total=( 
                    $user + $nice + $system + $idle 
                    + $iowait + $irq + $softirq
                );

                if ( defined( $cpu_idle_totals[$cpu_number] ) ) {
                    my $idle_delta=$idle-$cpu_idle_totals[$cpu_number];
                    my $total_delta=$total-$cpu_total_totals[$cpu_number];
                    my $usage=100 * (($idle_delta)/$total_delta);
                    printf("%s is %0.2f%% idle\n",$tag,$usage);

                    if ( $usage >= $threshold ) {
                        $cpu_idle_count++;
                    }
                }

                $cpu_idle_totals[$cpu_number]=$idle;
                $cpu_total_totals[$cpu_number]=$total;

            }
        }

        $output_fh->close();
        sleep $delta_time_sleep;
    }


    return $cpu_idle_count;
} 

输出:

cpu0 is 89.90% idle
cpu1 is 94.97% idle
cpu2 is 95.02% idle
cpu3 is 97.00% idle
cpu4 is 96.98% idle
cpu5 is 98.48% idle
cpu6 is 97.99% idle
cpu7 is 95.98% idle
Cores over 90% free:7

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接