【问题标题】:Executing linux time command inside python在python中执行linux time命令
【发布时间】:2018-03-01 21:14:07
【问题描述】:

我想计算在 python 脚本中执行 c 程序所需的时间。我为此使用了 os.system() 函数。

os.system("{ time ./test.out < inp;} > out 2> exe_time")
  • test.out 是我的 c 可执行文件
  • inp 包含 c 的输入
  • out存储c程序的输出
  • exe_time 存储程序的执行时间。

我在 exe_time 中得到的结果是这样的

0.00user 0.00system 0:00.00elapsed ?%CPU (0avgtext+0avgdata 1416maxresident)k 0inputs+8outputs (0major+65minor)pagefaults 0swaps

但是当我在终端执行 { time ./test.out out 2> exe_time 时,我进入了 exe_time 文件

真正的 0m0.001s
用户 0m0.000s
系统 0m0.000s

如何使用 python 获得第二个版本的输出?

【问题讨论】:

  • 您从交互式 shell 中的 sh -c '{ time ./test.out &lt; inp;} &gt; out 2&gt; exe_time' 得到什么?这就是 system() 正在做的事情:它调用 /bin/sh,而不是 bash 或 zsh 或任何您的交互式 shell。
  • 如果你想要bash提供的time的实现,不要使用system();而是使用 subprocess.Popen(['bash', '-c', '{ time ./test.out &lt; inp;} &gt; out 2&gt; exe_time']) 之类的东西明确地指定 bash。
  • ...或者,更安全(如果您的文件名或参数不是常量):subprocess.Popen(['bash', '-c', 'in=$1; shift; out=$1; shift; err=$1; shift; { time "$@" &lt; "$in";} &gt; "$out" 2&gt; "$err"', '_', 'inp', 'out', 'exe_time', './test.out']) 从代码中带外传递参数。

标签: python linux shell time subprocess


【解决方案1】:

使用bash 调用您的代码,而不是/bin/shsystem() 的默认设置):

subprocess.Popen(['bash', '-c', '{ time ./test.out < inp;} > out 2> exe_time'])

但是请注意,上面的代码参数化以使用任意文件名是不安全的。一个更好的实践实现可能看起来像:

o, e = subprocess.Popen(['bash', '-c', 'time "$@" 2>&1', '_', './test.out'],
                        stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()

print("Output from command is:")
sys.stdout.write(o + "\n")
print("Output from time is:")
sys.stdout.write(e + "\n")

注意:

  • 我们明确调用 bash,从而确保使用其内置的 time 实现。
  • 从 shell 脚本带外传递参数可以安全地将任意参数传递给正在运行的脚本,而不必担心这些参数是否包含尝试的 shell 注入攻击。
  • 在 shell 脚本中重定向 2&gt;&amp;1 可确保 test.out 编写的任何 stderr 都与其他输出连接,而不是与 time 命令的输出混合。
  • 如果我们确实想要将输出重定向到文件,更好的做法是从 Python 中做到这一点,就像 stdout=open('out', 'w'), stderr=open('exe_time', 'w') 一样。

【讨论】:

  • 子进程命令中的“_”代表什么?假设如果我必须从文件中读取 inp,我可以在子进程命令中给出 './test.out
  • @Perseus14,_ 变为 $0;因此,它是我们不关心的值的占位符,因为"$@" 仅扩展为$1 及以后。 stdin=open('inp_file', 'r') 从文件中读取,或 stdin=subprocess.PIPE 并将您的数据作为参数传递给 communicate()
  • 对不起@Charles,我没有收到命令。这是一个 o, e = subprocess.Popen(['bash', '-c', 'time "$@" 2>&1', '_', './test.out'], stdout=subprocess. PIPE,stdin= subprocess.PIPE,stderr=subprocess.PIPE).communicate(open("inp_file".'r').readline())
  • 如果您正在读取文件,则只需使用subprocess.Popen([...], stdin=open('inp_file', 'r'), stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()。我建议 stdin=subprocess.PIPE 使用 communicate() 的显式参数来提供一个明确的替代方案,如果您认为该文件是强制性的,而不是如果它的使用对您的用例实际上是明智的。 (顺便说一句,如果你想传递整个文件,它只是read(),而不是readline)。
  • 谢谢@Charles!!一切运作良好。 (是的,你是对的 read() 是合适的,但我的文件只包含一行,所以没关系)
【解决方案2】:

os.system() 使用/bin/sh。 Bash 有自己的 time 内置函数,而不是 time 二进制文件:

$ /usr/bin/time ls /asd
ls: /asd: No such file or directory
        0.00 real         0.00 user         0.00 sys
$ time ls /asd
ls: /asd: No such file or directory

real    0m0.018s
user    0m0.008s
sys     0m0.013s

如果您想查看执行命令需要多长时间,只需使用subprocess

import time
import subprocess

with open('inp', 'rb') as input_file:
    with open('out', 'wb') as output_file:
        start = time.time()
        subprocess.call(['./test.out'], stdin=input_file, stdout=output_file)
        runtime = time.time() - start

【讨论】:

  • 如果 OP 只想要挂钟时间,后一种方法(比较 Python 中的 time.time())绝对是正确的选择。如果他们关心用户/系统/挂钟拆分,那可能还不够。
猜你喜欢
  • 1970-01-01
  • 2017-07-30
  • 2014-04-22
  • 1970-01-01
  • 2012-10-09
  • 2011-06-11
  • 2021-08-19
  • 2021-05-26
  • 1970-01-01
相关资源
最近更新 更多