2010-01-06 11 views
7

Je fais beaucoup de recherche de fichier basé sur un critère dans plusieurs itérations de mon script Perl et il semble prendre 100% du temps CPU. Existe-t-il un moyen de contrôler mon utilisation du processeur de script? J'ai lu quelque part à propos de mettre des cycles de sommeil vides dans mon script. Mais je ne suis pas sûr de savoir comment faire cela.Contrôler l'utilisation du processeur d'un script perl?

+0

Ceci dépend de la plate-forme. Quel système d'exploitation utilisez-vous? –

+1

@bish S'il n'y a pas d'autres processus nécessitant la CPU, pourquoi devrait-il le laisser, gaspiller de bons cycles quand ils peuvent être mis à profit? – Eli

+0

Je cours mes manuscrits sur Windows. Oui, d'autres processus sont également en cours d'exécution. Je devais être moins intrusif avec mes scripts. –

Répondre

10

vous pourriez réduire le processus de priorité (Perl de), attribué par le système d'exploitation: windows ou linux

exemple pour priorité la plus basse:

fenêtres

start /LOW perl <myscript> 

linux

nice +19 perl <myscript> 
+0

Cela ressemble à la solution la plus simple. Je vais essayer cela avant les autres et faire un rapport. –

+0

Ceci est une solution facile, mais nécessite la connaissance des utilisateurs ou que vous créez un script de démarrage ou un alias. Cependant, si vous utilisez setpriority(), le code reniera/changera la priorité comme prévu. Le type d'application et d'utilisation doit décider quelle solution choisir. –

3

juste dormir:

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

ou un peu plus de fantaisie, faire des opérations N par cycle de sommeil:

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. 
    } 
} 
+0

Ok. J'ai l'idée. Je vais donc devoir décomposer mes tâches en groupes pouvant être itérés. –

5

Vous pouvez utiliser sleep or usleep. Une autre chose que vous pouvez faire est de réduire la priorité du processus.

Mise à jour: Voir setpriority()

+0

La fonction 'setpriority' de Perl est juste une enveloppe autour de l'appel système avec le même nom. En tant que tel, c'est une erreur fatale de l'appeler sur les plates-formes qui ne l'implémentent pas (par exemple Windows). –

+0

Je viens de le confirmer. 'setpriority()' n'est pas implémenté dans Windows. –

7

Une excellente façon d'améliorer l'utilisation du processeur est d'utiliser de meilleurs algorithmes. Ne devinez pas où votre code passe tout son temps: utilisez un profileur. Devel::NYTProf est un outil fantastique pour cela.

Assurez-vous de garder à l'esprit Amdahl's law. Par exemple, disons qu'une partie de votre programme utilise un algorithme quadratique et qu'avec un peu d'effort, vous pouvez le remplacer par un algorithme linéaire. Hourra! Mais si le code en question ne représente que 5% de l'exécution totale, votre effort le plus héroïque ne peut apporter qu'une amélioration minime de cinq pour cent. Utilisez un profileur pour déterminer si des opportunités pour une accélération plus rapide sont disponibles ailleurs. Vous ne nous dites pas ce que vous recherchez, et même les algorithmes les plus connus peuvent être gourmands en ressources CPU. Considérez que le planificateur de votre système d'exploitation a été écrit, réglé à la main, testé et réécrit pour utiliser efficacement les ressources du système. Oui, certaines tâches nécessitent des planificateurs spécialisés, mais de tels cas sont rares, d'autant plus rares que vous utilisez Perl. Ne considérez pas comme un mauvais signe que votre code consomme du CPU. Vous serez peut-être surpris d'apprendre que l'un des défis les plus difficiles dans les systèmes en temps réel, où les performances sont cruciales, est de garder le processeur occupé au lieu de le laisser tourner au ralenti.

+0

Mon script passe beaucoup de temps à faire des tâches subalternes, comme chercher du texte dans des fichiers, exécuter des programmes externes, capturer et analyser leur sortie, plutôt que n'importe quel algorithme spécialisé. En général, je suis d'accord avec votre opinion. Je ne suis pas particulièrement inquiet que mon script mange le CPU. Mais plus avec le fait que cette utilisation du processeur affecte d'autres programmes et services fonctionnant sur le même serveur Windows. Alors c'est tout. Une priorité de processus simple et faible semble servir mon objectif à l'heure actuelle. Oui, le profilage est bon à long terme. –

+0

Semble comme un choix intelligent. –

+0

Merci pour le conseil sur NYTProf! note à moi-même: la seule sorte d'un guide avec des mesures que j'ai pu trouver jusqu'à présent est [perlmonks: mod_perl application profiling - Problème] (http://www.perlmonks.org/?node_id=833194) .. Cheers! – sdaau

2

sleep + time + times pouvez le faire un peu.

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

(... Untested) Saupoudrez assez relax appels tout au long de votre code et cela devrait moyenner à proximité ou moins de 50% du temps CPU.


BSD::Resource peut faire moins effractive, et vous pourriez aussi bien saisir Time::HiRes pour une plus grande précision.

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

(également non testé ...) Sur un système qui le soutient, cela devrait demander à l'OS de vous signaler toutes les $interval secondes de temps CPU, au cours de laquelle vous pointez réinitialiser le compteur et le sommeil. Cela ne devrait pas nécessiter de modifications au reste de votre code.

+0

Doit être testé. Mais ressemble à une solution intéressante pour contrôler généralement l'utilisation du processeur avec des nombres. –

2

Votre script fonctionne-t-il réellement tout le temps? Par exemple, si vous calculez un ensemble mandelbrot, vous aurez des boucles qui consomment du CPU, mais qui traitent activement les données tout le temps.

Ou avez-vous des boucles où vous êtes en attente pour plus de données à traiter:

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

Dans le premier cas, la priorité est mise sans doute la meilleure solution. Cela ralentira le calcul, mais seulement autant que nécessaire pour traiter tous les autres processus du système.

Dans le second cas, vous pouvez améliorer considérablement l'utilisation du processeur en ne dormant qu'une fraction de seconde.

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

Si vous tirez des données à partir d'une source qui select peut fonctionner sur, tant mieux. Vous pouvez faire en sorte que votre boucle se bloque jusqu'à ce que les données soient prêtes.

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

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

Sélectionnez les travaux sur les sockets et les handles de fichiers sur les systèmes * NIX. Sur les systèmes Windows, vous ne pouvez sélectionner que les sockets.