Python: ulimit e piacevole per subprocess.call / subprocess.Popen?
Domanda
devo limitare la quantità di tempo e CPU presa da esterni applicazioni a riga di comando che Spawn da un processo Python usando subprocess.call, soprattutto perché a volte il processo generato si blocca e blocca il CPU al 99%.
bello e ulimit sembrano modi ragionevoli per fare questo, ma io non sono sicuro di come si erano interagiscono con sottoprocesso.
- I limiti sono qualcosa del tipo:
- Uccidere il processo se si sta prendendo più di 60 secondi
- limitarla al 20% della cpu
- voglio applicare la risorsa limitando al sottoprocesso, non al processo di pitone che sta generando i sottoprocessi.
C'è un modo per applicare bello e ulimit al subprocess.call processo generato? Ci sono migliori alternative python-native?
Questo è su un sistema Linux (Ubuntu).
Soluzione
È possibile impostare dei limiti per sottoprocessi con i comandi di shell ulimit
e nice
come questo:
import subprocess
subprocess.Popen('ulimit -t 60; nice -n 15 cpuhog', shell=True)
Questo esegue cpuhog
con un limite di 60 secondi di tempo di CPU ed una regolazione di priorità di 15. Si noti che non esiste un modo semplice per impostare un acceleratore CPU 20% come tale. Il processo sarà utilizzare il 100% della CPU a meno che un altro (meno bello) processo deve anche la CPU.
Altri suggerimenti
Utilizzare il parametro preexec_fn a subprocess.Popen, e il modulo di risorse. Esempio:
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 si biforca in un nuovo processo. Nel nuovo processo, chiamerà setlimits (), poi exec child.py . Questo significa che la risorsa sarà limitato nel processo figlio, ma non nel genitore.
Output quando si programma in esecuzione:
./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)
Questo è in molti casi una soluzione migliore che cercare di usare ulimit, dato che non è sempre una buona idea per deporre le uova sottoprocesso via shell, soprattutto dal momento che è spesso causa di brutto parametro guai citando.
Erik ha reso facile per me, ma ha dimenticato la parte nice
che Rich a punta fuori. Trovo il pacchetto psutil
bello (gioco di parole), ma purtroppo meno portabile. Ecco il mio prendere la questione:
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 utilizza il shell=True
per cui sono in qualche modo allergica. Forse sono solo vecchio e scontroso qui, ma cerco di evitarlo!