Aquí está el código de Python para ejecutar un comando arbitrario que devuelve sus stdout
datos, o generar una excepción en los códigos de salida distintos de cero:
proc = subprocess.Popen(
cmd,
stderr=subprocess.STDOUT, # Merge stdout and stderr
stdout=subprocess.PIPE,
shell=True)
communicate
se usa para esperar a que salga el proceso:
stdoutdata, stderrdata = proc.communicate()
El subprocess
módulo no admite el tiempo de espera (la capacidad de eliminar un proceso que se ejecuta durante más de X número de segundos), por lo tanto, communicate
puede tardar una eternidad en ejecutarse.
¿Cuál es la forma más sencilla de implementar tiempos de espera en un programa Python destinado a ejecutarse en Windows y Linux?
python
multithreading
timeout
subprocess
Sridhar Ratnakumar
fuente
fuente
Respuestas:
En Python 3.3+:
output
es una cadena de bytes que contiene datos stdout, stderr combinados del comando.check_output
aumentaCalledProcessError
en el estado de salida distinto de cero como se especifica en el texto de la pregunta a diferencia delproc.communicate()
método.He eliminado
shell=True
porque a menudo se usa innecesariamente. Siempre puede volver a agregarlo sicmd
realmente lo requiere. Si agregashell=True
, es decir, si el proceso hijo genera sus propios descendientes;check_output()
puede regresar mucho más tarde de lo que indica el tiempo de espera, vea Falla del tiempo de espera del subproceso .La función de tiempo de espera está disponible en Python 2.x a través del
subprocess32
backport del módulo de subproceso 3.2+.fuente
check_output()
es la forma preferida de obtener salida (devuelve la salida directamente, no ignora los errores, está disponible desde siempre). 2-run()
es más flexible perorun()
ignora el error por defecto y requiere pasos adicionales para obtener la salida 3-check_output()
se implementa en términos derun()
y, por lo tanto, acepta la mayoría de los mismos argumentos. 4- nit:capture_output
está disponible desde 3.7, no 3.5No sé mucho sobre los detalles de bajo nivel; pero, dado que en python 2.6 la API ofrece la capacidad de esperar subprocesos y finalizar procesos, ¿qué pasa con la ejecución del proceso en un subproceso separado?
El resultado de este fragmento en mi máquina es:
donde se puede ver que, en la primera ejecución, el proceso finalizó correctamente (código de retorno 0), mientras que en la segunda el proceso finalizó (código de retorno -15).
No he probado en Windows; pero, aparte de actualizar el comando de ejemplo, creo que debería funcionar ya que no he encontrado en la documentación nada que diga que thread.join o process.terminate no sea compatible.
fuente
La respuesta de jcollado se puede simplificar usando la clase threading.Timer :
fuente
lambda
:t = Timer(timeout, proc.kill)
timer.isAlive()
antestimer.cancel()
significa que terminó normalmenteSi estás en Unix,
fuente
Aquí está la solución de Alex Martelli como un módulo con la eliminación adecuada del proceso. Los otros enfoques no funcionan porque no usan proc.communicate (). Entonces, si tiene un proceso que produce mucha salida, llenará su búfer de salida y luego se bloqueará hasta que lea algo de él.
fuente
ValueError: signal only works in main thread
He modificado la respuesta de sussudio . Ahora función devuelve: (
returncode
,stdout
,stderr
,timeout
) -stdout
ystderr
se decodifica a UTF-8 cuerdasfuente
sorprendido nadie mencionó usar
timeout
timeout 5 ping -c 3 somehost
Obviamente, esto no funcionará para todos los casos de uso, pero si se trata de un script simple, es difícil de superar.
También disponible como gtimeout en coreutils a través
homebrew
de usuarios de mac.fuente
proc = subprocess.Popen(['/usr/bin/timeout', str(timeout)] + cmd, ...)
. ¿Hay untimeout
comando en Windows como OP pregunta?timeout
ahora es compatible concall()
ycommunicate()
en el módulo de subproceso (a partir de Python3.3):Esto llamará al comando y generará la excepción
si el comando no termina después de 20 segundos.
Luego puede manejar la excepción para continuar su código, algo como:
Espero que esto ayude.
fuente
timeout
parámetro . Aunque mencionarlo una vez más no estaría de más.Otra opción es escribir en un archivo temporal para evitar el bloqueo stdout en lugar de tener que sondear con comunicar (). Esto funcionó para mí donde las otras respuestas no lo hicieron; por ejemplo en windows.
fuente
No sé por qué no se menciona, pero desde Python 3.5, hay un nuevo
subprocess.run
comando universal (que está destinado a reemplazarcheck_call
,check_output
...) y que tiene eltimeout
parámetro.Provoca una
subprocess.TimeoutExpired
excepción cuando el tiempo de espera ha expirado.fuente
Aquí está mi solución, estaba usando Thread and Event:
En acción:
fuente
La solución que uso es prefijar el comando de shell con timelimit . Si el comando tarda demasiado, timelimit lo detendrá y Popen tendrá un código de retorno establecido por timelimit. Si es> 128, significa que el límite de tiempo mató el proceso.
Consulte también el subproceso de python con tiempo de espera y salida grande (> 64K)
fuente
timeout
- packages.ubuntu.com/search?keywords=timeout - pero ninguna de las dos funciona en Windows, ¿verdad?Agregué la solución con subprocesos
jcollado
a mi módulo Python easyprocess .Instalar en pc:
Ejemplo:
fuente
si estás usando python 2, pruébalo
fuente
Anteponer el comando de Linux
timeout
no es una mala solución y funcionó para mí.fuente
He implementado lo que pude reunir de algunos de estos. Esto funciona en Windows, y como se trata de una wiki comunitaria, creo que también compartiría mi código:
Luego de otra clase o archivo:
fuente
terminate()
función marca un hilo como terminado, pero en realidad no termina el hilo! Puedo verificar esto en * nix, pero no tengo una computadora con Windows para probar.Una vez que comprenda el proceso completo que ejecuta la maquinaria en * unix, encontrará fácilmente una solución más simple:
Considere este ejemplo simple de cómo hacer que el método de comunicación () se pueda cronometrar usando select.select () (disponible casi en todas partes en * nix hoy en día). Esto también se puede escribir con epoll / poll / kqueue, pero la variante select.select () podría ser un buen ejemplo para usted. Y las principales limitaciones de select.select () (velocidad y 1024 fds máximos) no son aplicables para su tarea.
Esto funciona bajo * nix, no crea subprocesos, no usa señales, se puede iniciar desde cualquier subproceso (no solo principal) y lo suficientemente rápido como para leer 250 mb / s de datos desde stdout en mi máquina (i5 2.3ghz).
Hay un problema al unir stdout / stderr al final de la comunicación. Si tiene una gran salida de programa, esto podría llevar a un gran uso de memoria. Pero puede llamar a comunicarse () varias veces con tiempos de espera más pequeños.
fuente
Puedes hacer esto usando
select
fuente
He usado killableprocess con éxito en Windows, Linux y Mac. Si está utilizando Cygwin Python, necesitará la versión de OSAF de killableprocess porque de lo contrario los procesos nativos de Windows no serán eliminados.
fuente
Aunque no lo he mirado extensamente, este decorador que encontré en ActiveState parece ser bastante útil para este tipo de cosas. Junto con
subprocess.Popen(..., close_fds=True)
, al menos, estoy listo para el script de shell en Python.fuente
Esta solución mata el árbol de procesos en caso de shell = True, pasa parámetros al proceso (o no), tiene un tiempo de espera y obtiene la salida stdout, stderr y proceso de la llamada (usa psutil para kill_proc_tree). Esto se basó en varias soluciones publicadas en SO, incluidas las de jcollado. Publicación en respuesta a los comentarios de Anson y jradice en la respuesta de jcollado. Probado en Windows Srvr 2012 y Ubuntu 14.04. Tenga en cuenta que para Ubuntu necesita cambiar la llamada parent.children (...) a parent.get_children (...).
fuente
Existe la idea de subclasificar la clase Popen y extenderla con algunos decoradores de métodos simples. Llamémoslo ExpirablePopen.
fuente
Tuve el problema de que quería terminar un subproceso de subprocesos múltiples si tardaba más de un tiempo de espera determinado. Quería establecer un tiempo de espera
Popen()
, pero no funcionó. Entonces, me di cuenta de quePopen().wait()
es igualcall()
y tuve la idea de establecer un tiempo de espera dentro del.wait(timeout=xxx)
método, que finalmente funcionó. Por lo tanto, lo resolví de esta manera:fuente
Desafortunadamente, estoy sujeto a políticas muy estrictas sobre la divulgación del código fuente por parte de mi empleador, por lo que no puedo proporcionar el código real. Pero para mi gusto, la mejor solución es crear una subclase que anule la
Popen.wait()
encuesta en lugar de esperar indefinidamente yPopen.__init__
aceptar un parámetro de tiempo de espera. Una vez que haga eso, todos los demásPopen
métodos (que llamanwait
) funcionarán como se espera, incluidoscommunicate
.fuente
https://pypi.python.org/pypi/python-subprocess2 proporciona extensiones al módulo de subproceso que le permiten esperar hasta un cierto período de tiempo, de lo contrario, finalizar.
Por lo tanto, esperar hasta 10 segundos para que el proceso finalice, de lo contrario, elimine:
Esto es compatible con Windows y Unix. "results" es un diccionario, contiene "returnCode", que es el retorno de la aplicación (o None si se tuvo que eliminar), así como "actionTaken". que será "SUBPROCESS2_PROCESS_COMPLETED" si el proceso se completa normalmente, o una máscara de "SUBPROCESS2_PROCESS_TERMINATED" y SUBPROCESS2_PROCESS_KILLED dependiendo de la acción realizada (consulte la documentación para obtener más detalles)
fuente
para python 2.6+, use gevent
fuente
python 2.7
fuente
fuente
Solo estaba tratando de escribir algo más simple.
fuente