Subproceso de Python con / usr / bin / time: ¿cómo capturar información de tiempo pero ignorar todas las demás salidas?

Estoy tratando de medir el tiempo de ejecución en segundos de un progtwig ejecutable invocado a través de un subproceso. No quiero que se emita la salida del ejecutable (ya sea stderr o stdout).

He probado las bibliotecas timeit y resource, pero ninguna captura con precisión el tiempo del proceso, al parecer, solo captura la sincronización en el subproceso de trabajo de Python.

Este bash a continuación perderá la información de tiempo b / c del redireccionamiento stderr. Sin embargo, sin la redirección de stderr, se emitirá el comando ‘f_cmd’ salida de stderr.

def doWithTiming(f_cmd): DEVNULL = open(os.devnull, 'w') return subprocess.check_output([ "/usr/bin/time", "--format=%e seconds"] + f_cmd.split(), stderr=DEVNULL) 

¿Cómo ignoro toda la salida de f_cmd pero retengo la salida de / usr / bin / time?

%e formato %e /usr/bin/time es :

Tiempo real transcurrido (reloj de pared) utilizado por el proceso, en segundos.

Para ejecutar un subproceso con stdout / stderr suprimido y obtener el tiempo transcurrido:

 #!/usr/bin/env python import os import time from subprocess import check_call, STDOUT DEVNULL = open(os.devnull, 'wb', 0) start = time.time() check_call(['sleep', '1'], stdout=DEVNULL, stderr=STDOUT) print("{:.3f} seconds".format(time.time() - start)) 

timeit.default_timer es time.time en POSIX en Python 2, por lo tanto, debe tener un tiempo válido a menos que su uso de timeit sea ​​incorrecto.


La información devuelta por el módulo de resource no incluye el tiempo “real”, pero podría usarlo para obtener los tiempos de “usuario” y “sys”, es decir, “Número total de segundos de CPU que el proceso pasó en el modo de usuario”. y “Número total de segundos de CPU que el proceso pasó en modo kernel”. correspondientemente

 #!/usr/bin/env python import os import time from subprocess import Popen, STDOUT DEVNULL = open(os.devnull, 'wb', 0) start = time.time() p = Popen(['sleep', '1'], stdout=DEVNULL, stderr=STDOUT) ru = os.wait4(p.pid, 0)[2] elapsed = time.time() - start print(" {:.3f}real {:.3f}user {:.3f}system".format( elapsed, ru.ru_utime, ru.ru_stime)) 

Puede iniciar un subproceso usando psutil.Popen y obtener mientras el proceso hijo ejecuta información adicional (CPU, memoria, conexiones de red, subprocesos, archivos, archivos, etc.) de forma portátil.

Vea también, Cómo obtener el máximo uso de memoria de un progtwig usando psutil en Python .


Para las pruebas (para asegurarse de que la solución basada en time.time() produzca los mismos resultados), podría capturar /usr/bin/time output:

 #!/usr/bin/env python import os from collections import deque from subprocess import Popen, PIPE DEVNULL = open(os.devnull, 'wb', 0) time_lines_count = 1 # how many lines /usr/bin/time produces p = Popen(['/usr/bin/time', '--format=%e seconds'] + ['sleep', '1'], stdout=DEVNULL, stderr=PIPE) with p.stderr: q = deque(iter(p.stderr.readline, b''), maxlen=time_lines_count) rc = p.wait() print(b''.join(q).decode().strip()) 

O usando la opción -o con una tubería con nombre:

 #!/usr/bin/env python import os from contextlib import contextmanager from shutil import rmtree from subprocess import Popen, STDOUT from tempfile import mkdtemp DEVNULL = open(os.devnull, 'wb', 0) @contextmanager def named_pipe(): dirname = mkdtemp() try: path = os.path.join(dirname, 'named_pipe') os.mkfifo(path) yield path finally: rmtree(dirname) with named_pipe() as path: p = Popen(['/usr/bin/time', '--format=%e seconds', '-o', path] + ['sleep', '1'], stdout=DEVNULL, stderr=STDOUT) with open(path) as file: time_output = file.read().strip() rc = p.wait() print(time_output) 

Su problema no es tanto con Python como con el comportamiento de la utilidad de tiempo de linux. el tiempo se escribirá en stderr después de cualquier mensaje stderr que el proceso escriba. Obtendrías este efecto ejecutándolo desde el shell. El subproceso copiará exactamente el comportamiento del comando de shell.

Le sugiero que redirija stderr a suprocess.PIPE y luego lo analice. No debería ser demasiado difícil.

Alternativamente, puede usar -o con tiempo para escribir su información de tiempo en un archivo de salida.