【问题标题】:python parallel processes return exit codepython并行进程返回退出代码
【发布时间】:2017-03-01 00:16:52
【问题描述】:

让我们看看我能否说清楚...我是一个 Python 初学者,所以请耐心等待,这是我的第一个 Python 程序(尽管我熟悉其他几种语言的基本脚本)。我已经搜索了好几个小时,我确信这个问题的答案相当简单,但我还没有让它正常工作。

我正在编写一个应该启动多个命令行进程的代码,当每个进程完成时,我想更新 QTableWidget 中的一个单元格。该表有一行供每个进程运行,每一行都有一个单元格表示进程的“状态”。

如果我只做一个 for 循环,每行使用subprocess.call() 生成一个进程,我可以运行这个没有问题,但是这太线性了,我想同时将它们全部关闭而不是挂起程序每个循环周期。我一直在研究子流程文档,并且很难使用它。我知道我需要使用subprocess.Popen(这将防止我的程序在进程运行时挂起,因此我可以生成多个实例)。我遇到麻烦的地方是取回退出代码,以便我可以更新我的表,而无需挂起程序 - 例如使用 subprocess.wait() 后跟 subprocess.returncode 仍然只是坚持到过程完成。我需要一种“当过程完成时,检查退出代码并运行更新 QTableWidget 的函数。”

我确实发现这两个帖子似乎让我朝着正确的方向前进,但并没有完全让我到达那里:

Understanding Popen.communicate

How to get exit code when using Python subprocess communicate method?

希望这是有道理的。这是我的代码的简化版本,我意识到它是半生不熟和半坏的,但我已经搞砸了一个多小时,我已经忘记了一些事情......

import os, subprocess

ae_app = 'afterfx'
ae_path = os.path.join('C:/Program Files/Adobe/Adobe After Effects CC 2015/Support Files', ae_app + ".exe")
filename = "E:/Programming/Python/Archive tool/talk.jsx"
commandLine = 'afterfx -noui -r ' + filename

processList = [commandLine]
processes = []

for process in processList:
    f = os.tmpfile()
    aeProcess = subprocess.Popen(process, executable=ae_path, stdout=f)
    processes.append((aeProcess, f))

for aeProcess, f in processes:
    # this is where I need serious help...
    aeProcess.wait()
    print "the line is:"
    print aeProcess.returncode
  • 斯宾塞

【问题讨论】:

    标签: python subprocess


    【解决方案1】:

    你提到了 PyQt,所以你可以使用 PyQt 的 QProcess 类。

    def start_processes(self, process_list):
        for cmd, args in process_list:
            proc = QProcess(self)
            proc.finished.connect(self.process_finished)
            proc.start(cmd, args)
    
    def process_finished(self, code, status):
        # Do something
    

    更新:添加了完整的工作示例。适用于 PyQt4 和 PyQt5(仅切换注释第 3 行和取消注释第 4 行)

    sleeper.py

    import sys
    from time import sleep
    from datetime import datetime as dt
    
    if __name__ == '__main__':
        x = int(sys.argv[1])
        started = dt.now().time()
        sleep(x)
        ended = dt.now().time()
        print('Slept for: {}, started: {}, ended: {}'.format(x, started, ended))
        sys.exit(0)
    

    main.py

    import sys
    
    from PyQt5 import QtCore, QtWidgets
    # from PyQt4 import QtCore, QtGui as QtWidgets
    
    
    class App(QtWidgets.QMainWindow):
        cmd = r'python.exe C:\_work\test\sleeper.py {}'
    
        def __init__(self):
            super(App, self).__init__()
            self.setGeometry(200, 200, 500, 300)
            self.button = QtWidgets.QPushButton('Start processes', self)
            self.button.move(20, 20)
            self.editor = QtWidgets.QTextEdit(self)
            self.editor.setGeometry(20, 60, 460, 200)
    
            self.button.clicked.connect(self.start_proc)
    
        def start_proc(self):
            for x in range(5):
                proc = QtCore.QProcess(self)
                proc.finished.connect(self.finished)
                proc.start(self.cmd.format(x))
    
        def finished(self, code, status):
            self.editor.append(str(self.sender().readAllStandardOutput()))
    
    
    if __name__ == '__main__':
        app = QtWidgets.QApplication(sys.argv)
        gui = App()
        gui.show()
        app.exec_()
    

    【讨论】:

    • 哇,不知道 PyQt 中存在这个!我遇到了一个错误,但我认为这是因为我错误地使用了 QProcess。在 codumentation 中看起来它需要 2 个参数:“cmd”和“args”,这就是我看到你设置 process_list 的方式。所以我想我的问题是——你能把它退后一步,告诉我你将如何设置“process_list”吗?它应该是一个元组还是什么?现在它只包含每个命令的字符串,该字符串是命令行文本
    • process_list = (('some.exe', '--some_params'), ('another.exe','-p 10 -r 20'))
    • 感谢您到目前为止的帮助,快到了! args 列表实际上必须是一个 QStringArray,我没有问题。我现在遇到的是,其中一个 args 是一个包含空格的文件路径,并且由于某种原因,它没有正确传递给进程(它不响应它)。从文档中:包含空格的参数用引号括起来。 所以我认为这是我的问题所在,因为我在没有引号的情况下运行子进程。有趣的是,如果我在 cmd 中用引号输入它,它工作正常......不知道下一步该做什么!
    • 哈,想出了一个解决方法!回顾文档时,我意识到您不需要在单独的数组中提供参数,您可以使用 program 参数将它们直接粉碎,这样可以防止 pyqt 弄乱您的字符串!
    • 啊!好吧,我用 QProcess 运行了所有东西,但现在我的 process_finished 函数没有运行。根据这个link,您无法从QProcess.startDetached() 获得已完成的信号!所以我认为这是错误的方向......回到子流程?
    猜你喜欢
    • 2022-01-22
    • 1970-01-01
    • 2017-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多