7

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

4

6 回答 6

10

您可以降低操作系统分配的进程(Perl)优先级: windowslinux

最低优先级的示例:

视窗

start /LOW  perl <myscript>

linux

nice +19 perl <myscript>
于 2010-01-06T12:32:37.153 回答
7

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

请务必牢记阿姆达尔定律。例如,假设您的程序的一部分使用了二次算法,并且您可以通过一些努力将其替换为线性算法。万岁!但是如果有问题的代码只占总运行时间的 5%,那么你最英勇的努力只能带来 5% 的微小改进。使用分析器确定其他地方是否有更大加速的机会。

你不会告诉我们你在搜索什么,即使是最知名的算法也可能是 CPU 密集型的。考虑到您的操作系统的调度程序已经过编写、手动调整、测试和重写,以有效地使用系统资源。是的,有些任务需要专门的调度程序,但这种情况很少见——考虑到您使用的是 Perl,这种可能性更小。

不要把它当作你的代码正在消耗 CPU 的坏信号。您可能会惊讶地发现,在性能至关重要的实时系统中,最困难的挑战之一就是让 CPU 保持忙碌而不是空闲。

于 2010-01-06T15:18:13.167 回答
5

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

更新:见setpriority()

于 2010-01-06T12:32:46.747 回答
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.
    }
}
于 2010-01-06T12:30:50.283 回答
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在整个代码中撒上足够多的调用,这应该平均接近或低于 50% 的 CPU 时间。


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

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

于 2010-01-06T16:52:29.827 回答
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;
}

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

于 2010-01-06T22:31:33.567 回答