控制perl脚本的CPU利用率?

时间:2010-01-06 12:28:06

标签: perl cpu-usage

我根据Perl脚本多次迭代的标准进行了大量的文件搜索,似乎占用了100%的CPU时间。有没有办法控制我的脚本CPU利用率?我读到了一些关于在我的脚本中放入空睡眠周期的地方。但我不知道该怎么做。

6 个答案:

答案 0 :(得分:10)

您可以降低操作系统指定的流程(Perl)优先级:windowslinux

最低优先级的示例:

windows

start /LOW  perl <myscript>

linux

nice +19 perl <myscript>

答案 1 :(得分:7)

提高CPU利用率的一个好方法是使用更好的算法。不要猜测代码在哪里花费所有时间:使用分析器。 Devel::NYTProf是一个很棒的工具。

请务必记住Amdahl's law。例如,假设您的程序的一部分使用二次算法,并且您可以使用线性算法替换它。万岁!但是,如果所讨论的代码仅占总运行时间的5%,那么您最英勇的努力不会带来微不足道的5%改进。使用分析器确定在其他地方是否有更高速度的机会。

您没有告诉我们您要搜索的内容,即使是最知名的算法也可能是CPU密集型的。考虑到您的操作系统的调度程序已经过编写,手动调整,测试和重写,以便有效地使用系统资源。是的,有些任务需要专门的调度程序,但是这种情况很少见 - 甚至不太可能,因为你使用的是Perl。

不要将其视为代码占用CPU的一个坏迹象。您可能会惊讶地发现,性能至关重要的实时系统中最难的挑战之一就是让CPU保持忙碌而不是闲置。

答案 2 :(得分:5)

您可以使用sleep or usleep。您可以做的另一件事是降低流程优先级。

更新: 见setpriority()

答案 3 :(得分:3)

睡觉:

while ($not_done_yet) {
    do_stuff_here();
    sleep 1; # <-- sleep for 1 second.
}

或稍微更花哨,每个睡眠周期进行N次操作:

my $op_count = 0;
while ($not_done_yet) {
    do_stuff_here();

    $op_count ++;
    if ($op_count >= 100) {
        $op_count = 0;
        sleep 1; # <-- sleep for 1 second every 100 loops.
    }
}

答案 4 :(得分:2)

sleep + time + times可以做到这一点。

my $base = time;
my $ratio = 0.5;
my $used = 0;
sub relax {
    my $now = time;
    my ($total) = times;
    return if $now - $base < 10 or $total - $used < 5;  # otherwise too imprecise
    my $over = ($total - $used) - $ratio * ($now - $base);
    $base = $now + ($over > 0 && sleep($over));
    $used = $total;
}

(未经测试......)在整个代码中调用足够relax个调用,这应该平均到CPU时间接近或低于50%。


BSD::Resource可以更少侵入性地执行此操作,您也可以抓取Time::HiRes以获得更高的精确度。

my $base = clock_gettime(CLOCK_MONOTONIC);
my (undef, $hard) = getrlimit(RLIMIT_CPU);
my $interval = 10;
if ($hard != RLIM_INFINITY && $hard < $interval) {$interval = $hard / 2}
my $ratio = 0.5;
$SIG{XCPU} = sub {
    setrlimit(RLIMIT_CPU, $interval, $hard);
    my $now = clock_gettime(CLOCK_MONOTONIC);
    my $over = $interval - $ratio * ($now - $base);
    $base = $now + ($over > 0 && sleep($over));
};
setrlimit(RLIMIT_CPU, $interval, RLIM_INFINITY);

(也未经测试...)在支持它的系统上,这应该要求操作系统每隔$interval秒的CPU时间向您发出信号,此时您将重置计数器并进入睡眠状态。这不应该要求对代码的其余部分进行任何更改。

答案 5 :(得分:2)

你的剧本实际上是在做什么吗?例如,如果你计算一个mandelbrot集,你将拥有消耗CPU的循环,但是它们一直在积极处理数据。

或者你有等待更多数据处理的循环:

while(1) { 
    process_data() if data_ready();
}

在第一种情况下,设置优先级可能是最佳解决方案。它会减慢计算速度,但只能为系统上任何其他进程提供服务所需的速度。

在第二种情况下,您可以通过仅仅几分之一秒的休眠来大幅提高CPU利用率。

while(1) { 
    process_data() if data_ready();
    select( undef, undef, undef, 0.1 );
}

如果您从select可以操作的来源提取数据,那就更好了。您可以安排循环阻止,直到数据准备就绪。

use IO::Select;
my $s = IO::Select->new($handle);

while(1) { 
    process_data() if $s->can_read;
}

选择适用于* NIX系统上的套接字和文件句柄。在Windows系统上,您只能选择套接字。