如何在子进程期间和之后做事
How to do stuff during and after a child process
我有一个调用子程序的程序。当子程序是 运行 Popen 时,我需要禁用 运行 按钮并启用停止按钮。但是,因为 Popen 开启了一个新的进程,程序结束后应该打印的东西会立即打印出来。我尝试在 Popen
之后添加 self.p.communicate()
,但是 GUI 将冻结直到子程序完成 运行ning,因此停止按钮将不起作用。
这是我的程序:
def gui(QtGui.QWidget):
...
self.runButton = QtGui.QPushButton('Run')
self.stopButton = QtGui.QPushButton('Stop')
self.runButton.clicked.connect(self.run)
self.stopButton.clicked.connect(self.kill)
self.runButton.setEnabled(True)
self.stopButton.setEnabled(False)
def run(self):
self.runButton.setEnabled(False)
self.p = subprocess.Popen(sample.exe)
#self.p.communicate()
self.stopButton.setEnabled(True)
print "Finish running" #without communicate() it will print out before .exe finish running
def kill(self):
self.p.kill()
self.stopButton.setEnabled(False)
print 'You have stop the program'
self.runButton.setEnabled(True)
我正在使用 Window7,Python 2.7,pyqt4。我不必使用子进程,任何打开并能够杀死子程序的东西都可以。
提前致谢。
编辑: 尝试按照 dano 的建议使用 QProcess
。我已将以下代码添加到我的程序中:
def gui(QtCore.Widget):
self.process = QtCore.QProcess(self)
def run(self):
self.process.start(exe_path)
self.process.started.connect(self.onstart)
self.process.finished.connect(self.onfinish)
self.runButton.setEnabled(False)
#self.p = subprocess.Popen(sample.exe) #removed
#self.p.communicate() #removed
def onstart (self):
self.stopButton.setEnabled(True)
self.runButton.setEnabled(False)
print "Started\n"
def onfinish (self):
self.stopButton.setEnabled(False)
self.runButton.setEnabled(True)
print "Finish running\n"
def kill(self):
self.process.kill()
#self.p.kill() #removed
这是输出:
点击"Run"(子程序结束后输出运行ning)
Finish running
第二次点击"Run"
Started
点击"Stop"
Finish running
Finish running
第三次点击"Run"
Started
Started
点击"Stop"
Finish running
Finish running
Finish running
这里发生了一些事情。
p = subprocess.Popen(exe)
不会等待 exe
完成 - 它 returns 一旦 exe
开始。
p.communicate()
会等待子进程结束,因此它会阻塞您的 GUI 线程(GUI 冻结直到子进程退出)。
为避免阻塞 GUI,您可以检查是否 p.poll()
returns None
以确定 p
进程是否仍在 运行。通常 GUI 框架提供了一种设置周期性回调的方法(例如,Qt 的 QTimer)——您可以在那里调用 p.poll()
。
或者将阻塞调用(例如p.wait()
)放入后台线程并在完成时通知GUI线程(发出信号,生成事件)。
QProcess 已经内置了通知机制(finished
信号)。
As :如果您不想多次调用回调,请不要多次连接同一个信号。在您的案例中,多次调用 .start()
同一个流程实例是没有意义的:
def run(self):
self.runButton.setEnabled(False) # call it first because
# processes are not started instantly
self.process = QtCore.QProcess(self)
self.process.started.connect(self.onstart) # connect "start" signal
self.process.finished.connect(self.onfinish)
self.process.start(exe_path, args) # then start
我有一个调用子程序的程序。当子程序是 运行 Popen 时,我需要禁用 运行 按钮并启用停止按钮。但是,因为 Popen 开启了一个新的进程,程序结束后应该打印的东西会立即打印出来。我尝试在 Popen
之后添加 self.p.communicate()
,但是 GUI 将冻结直到子程序完成 运行ning,因此停止按钮将不起作用。
这是我的程序:
def gui(QtGui.QWidget):
...
self.runButton = QtGui.QPushButton('Run')
self.stopButton = QtGui.QPushButton('Stop')
self.runButton.clicked.connect(self.run)
self.stopButton.clicked.connect(self.kill)
self.runButton.setEnabled(True)
self.stopButton.setEnabled(False)
def run(self):
self.runButton.setEnabled(False)
self.p = subprocess.Popen(sample.exe)
#self.p.communicate()
self.stopButton.setEnabled(True)
print "Finish running" #without communicate() it will print out before .exe finish running
def kill(self):
self.p.kill()
self.stopButton.setEnabled(False)
print 'You have stop the program'
self.runButton.setEnabled(True)
我正在使用 Window7,Python 2.7,pyqt4。我不必使用子进程,任何打开并能够杀死子程序的东西都可以。
提前致谢。
编辑: 尝试按照 dano 的建议使用 QProcess
。我已将以下代码添加到我的程序中:
def gui(QtCore.Widget):
self.process = QtCore.QProcess(self)
def run(self):
self.process.start(exe_path)
self.process.started.connect(self.onstart)
self.process.finished.connect(self.onfinish)
self.runButton.setEnabled(False)
#self.p = subprocess.Popen(sample.exe) #removed
#self.p.communicate() #removed
def onstart (self):
self.stopButton.setEnabled(True)
self.runButton.setEnabled(False)
print "Started\n"
def onfinish (self):
self.stopButton.setEnabled(False)
self.runButton.setEnabled(True)
print "Finish running\n"
def kill(self):
self.process.kill()
#self.p.kill() #removed
这是输出:
点击"Run"(子程序结束后输出运行ning)
Finish running
第二次点击"Run"
Started
点击"Stop"
Finish running
Finish running
第三次点击"Run"
Started
Started
点击"Stop"
Finish running
Finish running
Finish running
这里发生了一些事情。
p = subprocess.Popen(exe)
不会等待 exe
完成 - 它 returns 一旦 exe
开始。
p.communicate()
会等待子进程结束,因此它会阻塞您的 GUI 线程(GUI 冻结直到子进程退出)。
为避免阻塞 GUI,您可以检查是否 p.poll()
returns None
以确定 p
进程是否仍在 运行。通常 GUI 框架提供了一种设置周期性回调的方法(例如,Qt 的 QTimer)——您可以在那里调用 p.poll()
。
或者将阻塞调用(例如p.wait()
)放入后台线程并在完成时通知GUI线程(发出信号,生成事件)。
QProcess finished
信号)。
As .start()
同一个流程实例是没有意义的:
def run(self):
self.runButton.setEnabled(False) # call it first because
# processes are not started instantly
self.process = QtCore.QProcess(self)
self.process.started.connect(self.onstart) # connect "start" signal
self.process.finished.connect(self.onfinish)
self.process.start(exe_path, args) # then start