Comment limiter le temps d'exécution d'un programme sous Linux?

10

J'ai plusieurs simulations à faire, chacune est invoquée avec python simulate.py <parameter list>. Le problème avec ces simulations est que certaines d'entre elles se bloquent sans quitter, ce qui m'empêche de les exécuter en batch avec un simple script.

Ce dont j'ai besoin, c'est d'une forme de commande "run-time-constraint", qui tuerait automatiquement le processus (de préférence en appuyant virtuellement sur Ctrl + C , mais je pense que le simple kill fera aussi bien) après un temps spécifié, si le processus ne s'est pas terminé avec grâce par lui-même.

Bien sûr, je peux écrire un tel script moi-même, mais je soupçonne que quelqu'un l'a déjà fait avant moi, donc je n'ai pas à réinventer la roue en passant des heures avec ps, timeet en bash des manuels.

Adam Ryczkowski
la source

Réponses:

15

Solution potentielle # 1

Utilisez la timeoutcommande:

$ date
Mon May  6 07:35:07 EDT 2013
$ timeout 5 sleep 100
$ date
Mon May  6 07:35:14 EDT 2013

Vous pouvez également mettre un garde dans la timeoutcommande killsi elle ne s'est pas arrêtée après un certain temps.

$ date
Mon May  6 07:40:40 EDT 2013
$ timeout -k 20 5 sleep 100
$ date
Mon May  6 07:40:48 EDT 2013

Cela attendra jusqu'à 20 secondes après l' sleep 100arrêt du processus , s'il est toujours en cours, puis lui timeoutenverra un killsignal.

Solution potentielle # 2

Une méthode alternative, bien que plus risquée, serait la suivante:

./myProgram &
sleep 1
kill $! 2>/dev/null && echo "myProgram didn't finish"

Trouvé cette technique sur Stack Overflow dans une question intitulée: Limiter le temps d'exécution d'un programme sous Linux . Plus précisément cette réponse .

REMARQUE: selon un commentaire laissé par @mattdm, la méthode ci-dessus peut être risquée car elle suppose qu'il n'y a pas eu de nouveaux processus démarrés depuis votre processus. Aucun nouveau PID n'a donc été attribué. Compte tenu de cela, cette approche ne devrait probablement pas être utilisée mais n'est ici que comme référence pour une approche générale du problème. La timeoutméthode est la meilleure option du 2.

slm
la source
Mais alors il sera garanti que le script prendra toujours tout ce temps. Dans mon cas, ce n'est pas 1 seconde, mais plutôt 15 minutes.
Adam Ryczkowski
Mais l'autre solution trouvée dans cette question devrait être précisément ce dont j'ai besoin. Merci!
Adam Ryczkowski
2
Supposons que se myProgram termine en moins de temps que sleep(pas une hypothèse déraisonnable puisque l'objectif est de définir un temps d' exécution maximal autorisé). Vous envoyez ensuite un signal soit à un PID inexistant (aucun dommage réel fait) ou à tout processus aléatoire sur le système (potentiellement fatal).
un CVn
1
@ MichaelKjörling, merci pour le retour en arrière. J'ai mis à jour ma réponse en fonction du même commentaire que le PO a laissé également. On dirait que la timeoutcommande fait exactement ce qu'il cherche, en attendant que l'OP réponde à mes commentaires.
slm
@slm timeoutdevrait être la solution dont j'ai besoin. Je le teste en ce moment
Adam Ryczkowski
4

Je l' ai trouvé quelque chose d' un peu mieux, que timeout: timelimit.

Il présente plusieurs avantages; la première est que l'utilisateur peut annuler manuellement l'exécution en appuyant sur "Ctrl + C".

Le timelimitprogramme est disponible dans le référentiel Debian.

Adam Ryczkowski
la source
1
Essayer de comprendre les différences b / w timelimit et timeout. le délai peut être arrêté avec Ctrl + C. Quels sont les autres avantages?
slm
Eh bien, mon délai d'attente ne peut pas. J'utilise Mint 14 (basé sur Ubuntu Quantal).
Adam Ryczkowski
3

Vous pouvez régler le temps CPU et d'autres choses avec ulimit, pour le temps CPU en particulier:

$ ulimit -t 60      # limit to 60 seconds
$ program
RSFalcon7
la source
Voir ce Q&R U&L: unix.stackexchange.com/a/4666/7453 . @Gilles donne un bon aperçu de l'utilisation d'ulimit à cet effet.
slm
0

Bash utilise une variable appelée, $BASHPIDelle peut être utilisée dans une telle situation, par exemple:

#!/bin/bash
do_face() {
    local parent=$1
    echo $BASHPID > pid
    sleep 10
    echo "Killing parent $parent"
    kill $parent
}

ME=$BASHPID
eval $(echo "do_face $ME &")
sleep 20 && kill $(cat pid) && echo "killed child $(cat pid)"
exit 1

Vous pouvez changer l'argument de l'appel en sleepen do_face()au 100lieu de 10et voir ce qui se passe lorsque l'enfant prend trop de temps pour faire ses tâches. Modifiez simplement l'appel pour dormir en do_face()appel à votre exécutable et si cela prend trop de temps, le script le tuera, 20secondes est la valeur limite dans cet exemple. Les paramètres peuvent être implémentés afin que cela devienne un simple script à appeler et puisse être appelé par un autre script en batch ou autre. La gestion des fichiers pid pour chaque processus simultané est un problème qui devra être traité, peut-être utiliser des sous-répertoires différents ...

NB: Sur GNU Linux sleeppeut prendre des arguments en virgule flottante tels que sleep 0.1dormir pendant un dixième de seconde.

Overloaded_Operator
la source