Контролировать загрузку процессора сценария Perl? - PullRequest
7 голосов
/ 06 января 2010

Я выполняю большой поиск файлов на основе критериев в нескольких итерациях из моего сценария Perl, и он, похоже, занимает 100% процессорного времени. Есть ли способ контролировать загрузку процессора моего скрипта? Я где-то читал о включении пустых циклов сна в мой сценарий. Но я не уверен, как это сделать.

Ответы [ 6 ]

10 голосов
/ 06 января 2010

вы можете понизить приоритет процесса (Perl), назначенный ОС: windows или linux

пример для самого низкого приоритета:

windows

start /LOW  perl <myscript>

linux

nice +19 perl <myscript>
7 голосов
/ 06 января 2010

Отличный способ улучшить загрузку процессора - использовать лучшие алгоритмы. Не угадайте, где ваш код тратит все свое время: используйте профилировщик. Devel::NYTProf - фантастический инструмент для этого.

Обязательно помните закон Амдаля . Например, скажем, часть вашей программы использует квадратичный алгоритм, и с некоторым усилием вы можете заменить его линейным. Ура! Но если рассматриваемый код составляет только 5% от общего времени выполнения, ваши самые героические усилия не принесут ничего лучше, чем незначительное улучшение на пять процентов. Используйте профилировщик, чтобы определить, доступны ли возможности для ускорения в других местах.

Вы не говорите нам, что ищете, и даже самые известные алгоритмы могут загружать процессор. Учтите, что планировщик вашей операционной системы был написан, настроен вручную, протестирован и переписан для эффективного использования системных ресурсов. Да, для некоторых задач требуются специализированные планировщики, но такие случаи редки - даже менее вероятно, учитывая, что вы используете Perl.

Не воспринимайте это как плохой признак того, что ваш код загружает процессор. Вы можете быть удивлены, узнав, что одна из самых сложных задач в системах реального времени, где производительность имеет решающее значение, состоит в том, чтобы не загружать процессор, а загружать его.

5 голосов
/ 06 января 2010

Вы можете использовать sleep или usleep . Еще одна вещь, которую вы можете сделать, это понизить приоритет процесса.

Обновление: См. setpriority ()

3 голосов
/ 06 января 2010

Просто спать:

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.
    }
}
2 голосов
/ 07 января 2010

Ваш сценарий на самом деле все делает? Например, если вы вычислите набор Мандельброта, у вас будут циклы, которые потребляют ЦП, но постоянно обрабатывают данные.

Или у вас есть циклы, где вы ожидаете обработки дополнительных данных:

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

В первом случае установка приоритета, вероятно, является лучшим решением. Это замедлит вычисления, но только настолько, насколько это необходимо для обслуживания любых других процессов в системе.

Во втором случае вы можете радикально улучшить загрузку ЦП, спя всего за доли секунды.

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 вы можете выбирать только для сокетов.

2 голосов
/ 06 января 2010

сон + время + раз можно сделать это.

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% процессорного времени.


BSD :: Resource может сделать это менее инвазивно, и вы можете также захватить Время :: 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 секундыпроцессорного времени, в этот момент вы сбрасываете счетчик и спите.Это не должно требовать каких-либо изменений в остальной части вашего кода.

...