【问题标题】:How can I run two python subprocesses and grab their runtimes and stdout, stderr?如何运行两个 python 子进程并获取它们的运行时和标准输出、标准错误?
【发布时间】:2012-02-23 20:02:13
【问题描述】:

我正在考虑在一台机器上同时运行两个子进程,以便获得准确的运行时间。我正在比较两个版本的软件并对其运行诊断,例如运行时、输出变化等。

最初我有一个函数在同一个输入文件上使用软件的两个版本,并且每个输出到不同的位置。旧版本和新版本是通过 argparser 获取的。该函数对每个软件命令使用一个子进程,然后通过 .communicate() 抓取输出。但我知道 .communicate() 等待进程完成,理想情况下,我想同时在两个进程上使用 .communicate() 以便它们同时开始,并且是定时的,并且会在任何时候给我结果只要我知道它们的运行时间。

更简洁地说,我的问题是如何运行两个子进程,每个子进程分别单独运行并同时启动。然后获取它们的运行时和标准输出、标准错误?

这是我的函数的一个简单示例(只是假装我在某个文件上测试 java 的速度):

def test():
    # Get start time        
    before = time.time()
    cmd1 = ['java-1.0', 'blah']
    c1 = subprocess.Popen(cmd1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    cmd2 = ['java-1.5', 'blah']
    c2 = subprocess.Popen(cmd2, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    # Start both processes at the same time??
    results = [c1.communicate(), c2.communicate()]
    # Get total time taken
    total = round(time.time()-before, 2)
    # Print out the total time (I know its messy but its accurate)
    print "%s:%s:%s" % (int(total/60/60), int(total/60), int(total))
    c1.stderr.close()
    c2.stderr.close()
    return results

我要说明的另一点是,我需要它们同时运行,因为如果我在功能强大的远程机器(我将会)上运行作业,那么我需要在运行作业,这样一个进程就不会因为它在不同的时间运行而更快地完成。

【问题讨论】:

  • 与其假装,不如直接与我们联系。如果您真的在测试两个外部程序的速度,那么最好的方法将与您只需要运行一些东西完全不同(并且与您在此处编写的内容非常不同)。更详细地分享您想要完成的任务。
  • 您在这里使用round 并不理想(事实上,round 根本没有用处。)。如果要对秒数进行四舍五入,请使用 %0.2f 格式说明符之类的。
  • 我没有意识到像 round 这样的内置函数完全无关紧要,但这与解决我的问题没有任何关系。所以无论如何,你的意思是更直接?我没有假装什么,是的,我想在相同的数据上测试一个软件的两个不同版本,并比较它们的输出和速度。具体来说,我正在测试不同版本的 picard。较新的版本应该快 5 倍,所以我想对此进行测试并确保两个版本给出相同的结果!
  • 谁能帮忙,我卡住了。我真的需要这个来工作。

标签: python multithreading multiprocessing subprocess


【解决方案1】:

如果您试图获得准确 运行时,则需要多次运行测试并查看分布——运行时中位数应该是一个很好的指标。同时运行它们不会帮助您获得更准确的结果。

【讨论】:

    【解决方案2】:

    运行时测试通常在原本空闲的机器上进行,并在有或没有不同输入文件的情况下重复多次,以了解操作系统缓存的影响。

    让两个进程争夺相同的资源不会导致更准确的测量。

    加速 Python 程序通常需要使用正确的工具。例如。列表和其他理解通常比循环更快。使用内置函数可能胜过这一点。一个很好的例子是“an optimization anecdote”。最好的优化可能是不同的算法。

    使用 PyPy 代替 CPython 也可能会产生显着的改进。

    【讨论】:

    • 您关于 Python 优化的建议在此线程中似乎不合适,并且可能有害。 (你链接的文章有很多道理,但作为关于如何在 Python 中加快速度的实用建议,它已经过时了。)
    • 我的想法是,通常,当代码被认为很慢时,就会进行测量。您认为结论的哪一部分已经过时?
    【解决方案3】:

    在这种情况下,由于您没有要发送到进程的输入,因此您不需要使用Popen.communicate()。 Popen 调用本身会启动该过程,我们不需要Popen.communicate()。您可以使用Popen.poll() 来检查进程是否已完成,而不是使用 Popen.communicate()。

    while True:
        if c1.poll() is not None:
            #Stop c1's timer
        if c2.poll() is not None:
            #Stop c2's timer
    

    如果你想要 stdout 和 stderr,你可以生成 2 个线程,然后使用 Popen.communicate() 并记录时间。

    你可以使用这样的东西作为线程:

    def time_it(c):
        results.append(c.communicate())
        times.append(time.time())
    

    要生成线程,请调用

    results = []
    times = []
    threading.start_new_thread(time_it,(c1,))
    threading.start_new_thread(time_it,(c2,))
    

    【讨论】:

    • 既然他在收集这个过程的stdout和stderr,你的技术就不行了。
    • 我也在尝试保存标准输出和标准错误。
    • 如果需要stdout和stderr,可以在time_it函数中使用c.communicate()代替c.wait()
    • 您可能还想使用锁来确保始终正确附加数据。
    猜你喜欢
    • 1970-01-01
    • 2018-12-06
    • 2020-05-26
    • 2011-07-21
    • 2021-03-03
    • 1970-01-01
    • 2015-10-07
    • 2011-07-21
    • 2018-12-10
    相关资源
    最近更新 更多