使用/ usr/bin/time的Python子进程:如何捕获时序信息但忽略所有其他输出?

rke*_*emp 2 python time stdout stderr python-2.7

我试图测量通过子进程调用的可执行程序的执行时间(以秒为单位).我不希望发出可执行文件的输出(stderr或stdout).

我已经尝试了timeit和资源库,但是没有准确地捕获进程的时间,看起来它只捕获Python工作线程中的时间.

以下尝试将丢失stderr重定向的时间信息b/c.但是,如果没有stderr重定向,将发出命令'f_cmd'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)
Run Code Online (Sandbox Code Playgroud)

如何忽略f_cmd的所有输出但保留/ usr/bin/time的输出?

jfs*_*jfs 6

%e /usr/bin/time格式是:

过程使用的经过的实际(挂钟)时间,以秒为单位.

要使用抑制的stdout/stderr运行子进程并获取已用时间:

#!/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))
Run Code Online (Sandbox Code Playgroud)

timeit.default_timertime.time在Python 2上的POSIX上,因此除非您的使用timeit不正确,否则您应该有一个有效的时间.


resource模块返回的信息包括"实际"时间,但您可以使用它来获取"用户"和"sys"时间,即"进程在用户模式下花费的CPU总秒数"."进程在内核模式下花费的CPU总秒数." 相应地:

#!/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))
Run Code Online (Sandbox Code Playgroud)

你可以通过启动一个子进程psutil.Popen,并得到,而子进程运行在便携方式的附加信息(CPU,内存,网络连接,线程,FDS,儿童等).

另请参阅如何使用Python中的psutil获取程序的最大内存使用量.


为了测试(为了确保time.time()基于-based的解决方案产生相同的结果),您可以捕获/usr/bin/time输出:

#!/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())
Run Code Online (Sandbox Code Playgroud)

或者使用-o带有命名管道的选项:

#!/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)
Run Code Online (Sandbox Code Playgroud)