Python: ulimit et agréable pour subprocess.call / subprocess.Popen?
Question
Je dois limiter la quantité de temps et cpu pris par des applications de ligne de commande externes I Spawn à partir d'un processus de python en utilisant subprocess.call, principalement parce que parfois le processus est bloqué et donné naissance à l'épingle cpu à 99%.
agréable et ulimit semblent comme des moyens raisonnables pour ce faire, mais je ne sais pas comment ils avaient interagir avec le sous-processus.
- Les limites ressemblent à:
- Tuer le processus si elle prend plus de 60 secondes
- Limiter à 20% de cpu
- Je veux appliquer la ressource limitant à la sous-processus, pas au processus de python qui est fraie les sous-processus.
Y at-il un moyen d'appliquer agréable et ulimit au processus pondu subprocess.call? Y at-il de meilleures alternatives natif python?
Ceci est un système Linux (ubuntu).
La solution
Vous pouvez définir des limites pour les sous-processus avec des commandes shell ulimit
et nice
comme ceci:
import subprocess
subprocess.Popen('ulimit -t 60; nice -n 15 cpuhog', shell=True)
Cela va cpuhog
avec une limite de 60 secondes de temps CPU et un réglage de niceness de 15. Notez qu'il n'y a aucun moyen simple de définir un accélérateur de CPU 20% en tant que tel. Le processus utilisera 100% du CPU à moins qu'un autre processus (moins bien) a également besoin du CPU.
Autres conseils
Utilisez le paramètre preexec_fn à subprocess.Popen, et le module de ressources. Exemple:
parent.py:
#!/usr/bin/env python
import os
import sys
import resource
import subprocess
def setlimits():
# Set maximum CPU time to 1 second in child process, after fork() but before exec()
print "Setting resource limit in child (pid %d)" % os.getpid()
resource.setrlimit(resource.RLIMIT_CPU, (1, 1))
print "CPU limit of parent (pid %d)" % os.getpid(), resource.getrlimit(resource.RLIMIT_CPU)
p = subprocess.Popen(["./child.py"], preexec_fn=setlimits)
print "CPU limit of parent (pid %d) after startup of child" % os.getpid(), resource.getrlimit(resource.RLIMIT_CPU)
p.wait()
print "CPU limit of parent (pid %d) after child finished executing" % os.getpid(), resource.getrlimit(resource.RLIMIT_CPU)
child.py:
#!/usr/bin/env python
import os
import sys
import resource
print "CPU limit of child (pid %d)" % os.getpid(), resource.getrlimit(resource.RLIMIT_CPU)
parent.py fourchette dans un nouveau processus. Dans le nouveau processus, il appellera setLimits (), puis exec child.py . Cela signifie que la ressource sera limitée dans le processus de l'enfant, mais pas dans le parent.
sortie lorsque le programme en cours d'exécution:
./parent.py
CPU limit of parent (pid 17404) (-1, -1)
Setting resource limit in child (pid 17405)
CPU limit of parent (pid 17404) after startup of child (-1, -1)
CPU limit of child (pid 17405) (1, 1)
CPU limit of parent (pid 17404) after child finished executing (-1, -1)
Ceci est dans de nombreux cas, une meilleure solution que d'essayer d'utiliser ulimit, car il est pas toujours une bonne idée de se reproduire sous-processus via le shell, en particulier car il provoque souvent le paramètre laid citant des problèmes.
Erik , il était facile pour moi, mais il a oublié la partie qui nice
Rich Souligné. Je trouve le paquet psutil
agréable (jeu de mots) mais malheureusement moins portable. Voici mon opinion à la question suivante:
import os
import psutil
import resource
import subprocess
def preexec_fn():
pid = os.getpid()
ps = psutil.Process(pid)
ps.set_nice(10)
resource.setrlimit(resource.RLIMIT_CPU, (1, 1))
print "mother pid", os.getpid()
p = subprocess.Popen(["./cpuhog.sh"], preexec_fn=preexec_fn)
p.wait()
print "mother still alive with pid", os.getpid()
Ville a utilisé le shell=True
auquel je suis en quelque sorte allergique. Peut-être que je suis vieux et grincheux, mais je tente de l'éviter!