PyQt MainWindow 在 Windows 上使用多处理
PyQt MainWindow using multiprocessing on Windows
我尝试创建一个 PyQt
应用程序。为了 运行 在后台处理并保持 PyQt5
应用程序可用于新指令,我想使用 multiprocessing
。
在 Windows OS 上,当我使用 multiprocessing.process
从 Qt MainWindow
class 调用一个函数时,我在 pickling 这个 class 时出错.但它是 运行ning 在 Linux 上找到的。
这是一个例子:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import multiprocessing
#
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class Frame_main(QMainWindow):
def __init__(self, parent = None):
super(Frame_main, self).__init__(parent)
self.thrd_list=[]
self.initUI()
def initUI(self):
# Button
btn_run = QPushButton('Run', self)
btn_run.clicked.connect(lambda: self.ThdSomething(self.DoRun) ) #
btn_stop = QPushButton('Stop', self)
btn_stop.clicked.connect(self.DoStop)
### TEXT Edit
self.textEdit_term = QTextEdit("terminal: \n ")
self.textEdit_term.append("")
self.textEdit_term.setStyleSheet("color: rgb(255, 255, 255); background-color: black;")
self.textEdit_term.setLineWrapMode(QTextEdit.NoWrap)
self.textEdit_term.setToolTip(' terminal message ')
self.textEdit_term.setStatusTip('textEdit1')
### LAYOUT
Wid_main = QWidget() #
grid_major = QGridLayout() #
grid_major.addWidget( btn_run, 1, 5)
grid_major.addWidget( btn_stop, 2, 5)
Wid_main.setLayout(grid_major)
self.setCentralWidget(Wid_main)
### Affichage
self.show() #
#
def DoRun(self):
print('g starts')
time_start=time.time()
time_stop=time.time()
name='bob'
n=0
while time_stop-time_start <2 :
n+=1
time_stop=time.time()
time.sleep(0.8)
print ('hola', name,n, flush=True)
print('g stops')
def DoStop(self):
''' subourtine kill all the thread '''
print('stop action detected')
while len(self.thrd_list) > 0 :
print("Terminating the job: {}".format(self.thrd[-1].pid) )
os.kill(self.thrd[-1].pid, signal.SIGTERM)
self.thrd_list[-1].terminate()
self.thrd_list.pop()
def ThdSomething(self, job):
''' subourtine to create a new thread to do the job subroutine '''
arg=''
p=multiprocessing.Process(target=job, args=(arg))
self.thrd_list.append( p )
p.start()
print("Start the job GUI: {} with PID: {}".format(str(job) ,self.thrd[-1].pid), file=sys.stdout )
def closeEvent(self, event):
''' subroutine to define what happen when closing the main frame'''
self.statusBar().showMessage('waiting for a respond')
reply = QMessageBox.question(self, 'Message',
"Are you sure to quit?", QMessageBox.Yes |
QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()
# Main
if __name__ == '__main__':
# Create QApplication and Main Frame
Qapp = QApplication(sys.argv) # creation de lappli Qt
Qapp.setStyle("fusion") #
frame1 = Frame_main() #
sys.exit(Qapp.exec_()) #
编辑:
我发现了几个类似的案例,比如:
Python: multiprocessing in pyqt application
但其中 none 有帮助。我认为这可能与我的案例使用 MainWindow
class.
的函数和属性有关
你是对的,这是由于试图在 GUI 中分叉一个方法 class。不幸的是,windows 并不真正能够像 linux 那样分叉进程,这就是为什么您的代码在 linux 而不是 windows 上运行的原因。 Python 3 documentation for the multiprocessing library 提供了一些关于差异的有用信息,以及在不同平台下启动新进程的默认方法。
回答你的问题:因为你的目标是一个与 GUI 对象关联的方法,它必须将对象状态发送到新进程但无法 pickle 它,因为 PyQt GUI 对象太复杂而无法 pickle。
如果您重写代码以使目标函数(和指定的 args
)是可挑选的,您的代码将起作用。
我尝试创建一个 PyQt
应用程序。为了 运行 在后台处理并保持 PyQt5
应用程序可用于新指令,我想使用 multiprocessing
。
在 Windows OS 上,当我使用 multiprocessing.process
从 Qt MainWindow
class 调用一个函数时,我在 pickling 这个 class 时出错.但它是 运行ning 在 Linux 上找到的。
这是一个例子:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import multiprocessing
#
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class Frame_main(QMainWindow):
def __init__(self, parent = None):
super(Frame_main, self).__init__(parent)
self.thrd_list=[]
self.initUI()
def initUI(self):
# Button
btn_run = QPushButton('Run', self)
btn_run.clicked.connect(lambda: self.ThdSomething(self.DoRun) ) #
btn_stop = QPushButton('Stop', self)
btn_stop.clicked.connect(self.DoStop)
### TEXT Edit
self.textEdit_term = QTextEdit("terminal: \n ")
self.textEdit_term.append("")
self.textEdit_term.setStyleSheet("color: rgb(255, 255, 255); background-color: black;")
self.textEdit_term.setLineWrapMode(QTextEdit.NoWrap)
self.textEdit_term.setToolTip(' terminal message ')
self.textEdit_term.setStatusTip('textEdit1')
### LAYOUT
Wid_main = QWidget() #
grid_major = QGridLayout() #
grid_major.addWidget( btn_run, 1, 5)
grid_major.addWidget( btn_stop, 2, 5)
Wid_main.setLayout(grid_major)
self.setCentralWidget(Wid_main)
### Affichage
self.show() #
#
def DoRun(self):
print('g starts')
time_start=time.time()
time_stop=time.time()
name='bob'
n=0
while time_stop-time_start <2 :
n+=1
time_stop=time.time()
time.sleep(0.8)
print ('hola', name,n, flush=True)
print('g stops')
def DoStop(self):
''' subourtine kill all the thread '''
print('stop action detected')
while len(self.thrd_list) > 0 :
print("Terminating the job: {}".format(self.thrd[-1].pid) )
os.kill(self.thrd[-1].pid, signal.SIGTERM)
self.thrd_list[-1].terminate()
self.thrd_list.pop()
def ThdSomething(self, job):
''' subourtine to create a new thread to do the job subroutine '''
arg=''
p=multiprocessing.Process(target=job, args=(arg))
self.thrd_list.append( p )
p.start()
print("Start the job GUI: {} with PID: {}".format(str(job) ,self.thrd[-1].pid), file=sys.stdout )
def closeEvent(self, event):
''' subroutine to define what happen when closing the main frame'''
self.statusBar().showMessage('waiting for a respond')
reply = QMessageBox.question(self, 'Message',
"Are you sure to quit?", QMessageBox.Yes |
QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()
# Main
if __name__ == '__main__':
# Create QApplication and Main Frame
Qapp = QApplication(sys.argv) # creation de lappli Qt
Qapp.setStyle("fusion") #
frame1 = Frame_main() #
sys.exit(Qapp.exec_()) #
编辑:
我发现了几个类似的案例,比如:
Python: multiprocessing in pyqt application
但其中 none 有帮助。我认为这可能与我的案例使用 MainWindow
class.
你是对的,这是由于试图在 GUI 中分叉一个方法 class。不幸的是,windows 并不真正能够像 linux 那样分叉进程,这就是为什么您的代码在 linux 而不是 windows 上运行的原因。 Python 3 documentation for the multiprocessing library 提供了一些关于差异的有用信息,以及在不同平台下启动新进程的默认方法。
回答你的问题:因为你的目标是一个与 GUI 对象关联的方法,它必须将对象状态发送到新进程但无法 pickle 它,因为 PyQt GUI 对象太复杂而无法 pickle。
如果您重写代码以使目标函数(和指定的 args
)是可挑选的,您的代码将起作用。