2016-11-25 3 views
0

Я пытаюсь использовать модуль многопроцессорности в цикле for внутри класса PyQt. К сожалению, этот скрипт дает мне много ошибок. Вот сценарий, который просто отображает кнопку «Запустить» и запускает процесс в цикле, который печатает значение.RuntimeError и IOError при использовании многопроцессорности в скрипте PyQt

import multiprocessing 
from PyQt4 import QtGui 
import sys 

class SurfViewer(QtGui.QMainWindow): 
    def __init__(self, parent=None): 
     super(SurfViewer, self).__init__() 
     self.parent = parent 
     self.centralWidget = QtGui.QWidget() 
     self.setCentralWidget(self.centralWidget) 
     self.mainHBOX_param_scene = QtGui.QHBoxLayout() 
     self.Button_Run = QtGui.QPushButton('Run') 
     self.mainHBOX_param_scene.addWidget(self.Button_Run) 
     self.centralWidget.setLayout(self.mainHBOX_param_scene) 

     self.Button_Run.clicked.connect(self.Runclick) 

    def Runclick(self): 
     for i in range(5): 
      p = multiprocessing.Process(target=self.mp_worker,args=(i,)) 
      p.start() 

    def mp_worker(self,a): 
     print('a:' + str(a)) 
     return 

def main(): 
    app = QtGui.QApplication(sys.argv) 
    ex = SurfViewer(app) 
    ex.show() 
    sys.exit(app.exec_()) 

if __name__ == '__main__': 
    main() 

Я не понимаю, что я здесь делаю неправильно, так как ниже код работает хорошо:

import multiprocessing 

class maclass(): 
    def __init__(self,): 
     for i in range(5): 
      p = multiprocessing.Process(target=self.mp_worker , args=(i,)) 
      p.start() 

    def mp_worker(self,a): 
     print('a:' +str(a)) 
     return 

def main(): 
    maclass() 

if __name__ == '__main__': 
    main() 

Единственная разница в том, что делается нескольких процессов в Button_Run.clicked. event.

Ошибки я получаю (от первого сценария):

Traceback (most recent call last):

File "", line 1, in

File "C:\Anaconda2\lib\multiprocessing\forking.py", line 381, in main self = load(from_parent)

File "C:\Anaconda2\lib\pickle.py", line 1384, in load return Unpickler(file).load()

File "C:\Anaconda2\lib\pickle.py", line 864, in load dispatchkey

File "C:\Anaconda2\lib\pickle.py", line 1221, in load_build setstate = getattr(inst, "setstate", None)

RuntimeError: super-class init() of type QPushButton was never called

Но я также получаю другую ошибку, когда я пытаюсь использовать многопроцессный в моем большом приложении, например:

File "C:\Anaconda2\lib\pickle.py", line 492, in save_string

self.write(BINSTRING + pack(" i", n) + obj)

IOError: [Errno 32] Broken pipe

Возможно, это может быть связано с первой ошибкой.

Кто-нибудь уже видел решение этой проблемы?

Редактировать: Я попытался использовать приведенный ниже пример @ImportanceOfBeingErnest. Так вот новый код:

import multiprocessing 
from PyQt4 import QtGui 
import sys 

class maclass(): 
    def __init__(self,): 
     pass 

    def start(self, n): 
     lfp=[] 
     for i in range(n): 
      recv_end, send_end = multiprocessing.Pipe() 
      p = multiprocessing.Process(target=self.mp_worker , args=(i,send_end)) 
      p.start() 
      send_end.close() 
      lfp.append(recv_end.recv()) 
      recv_end.close() 
      print(i, lfp) 
     #p.join() 

    def mp_worker(self,a,send_end): 
     print('a:' +str(a)) 
     send_end.send(a) 
     return 

class SurfViewer(QtGui.QMainWindow): 
    def __init__(self, parent=None): 
     super(SurfViewer, self).__init__() 
     self.parent = parent 
     self.centralWidget = QtGui.QWidget() 
     self.setCentralWidget(self.centralWidget) 
     self.mainHBOX_param_scene = QtGui.QHBoxLayout() 
     self.Button_Run = QtGui.QPushButton('Run') 
     self.mainHBOX_param_scene.addWidget(self.Button_Run) 
     self.centralWidget.setLayout(self.mainHBOX_param_scene) 

     self.worker = maclass() 
     self.Button_Run.clicked.connect(self.start) 

    def start(self): 
     for k in range(5): 
      self.worker.start(4) 

def main(): 
    app = QtGui.QApplication(sys.argv) 
    ex = SurfViewer(app) 
    ex.show() 
    sys.exit(app.exec_()) 

if __name__ == '__main__': 
    main() 

В этом случае, я хотел бы получить результат от работника с recv_end, send_end = multiprocessing.Pipe(). Этот код отлично работает в том смысле, что я получаю правильный результат. К сожалению, кажется, что я теряю способность многопроцессорности. Я явно делаю что-то не так с трубой, но я не могу понять, что это такое.

+3

Ваша рабочая функция - это метод окна Qt. Это означает, что каждый новый процесс должен иметь это (или копию) этого окна. Windows не может быть отобрана и передана в новое окно. Вы должны отделить своего рабочего от пользовательского интерфейса. –

+0

Спасибо, что ответили. Это ответ, который я не хотел ...;) , потому что я хотел бы использовать рабочего как часть класса для изменения некоторых членов этого класса. – ymmx

ответ

1

Наконец-то я нашел решение моей проблемы. Вот код, который выполняет мультипроцессирование, а также обрабатывать результат возвращения из многопоточной работника:

import multiprocessing 
from PyQt4 import QtGui 
import sys 

class maclass(): 

    def __init__(self,): 
     pass 
    @classmethod 
    def start(self, n): 
     lfp=[] 
     r=[] 
     for i in range(n): 
      # queue = multiprocessing.Queue() 
      recv_end, send_end = multiprocessing.Pipe() 
      p = multiprocessing.Process(target=self.mp_worker , args=(i,send_end)) 
      p.start() 
      r.append(recv_end) 
     for recv_end in r: 
      lfp.append(recv_end.recv()) 
      print(i, lfp) 
    @classmethod 
    def mp_worker(self,a,send_end): 
     print('a:' +str(a)) 
     send_end.send(a) 
     return 


class SurfViewer(QtGui.QMainWindow): 
    def __init__(self, parent=None): 
     super(SurfViewer, self).__init__() 
     self.parent = parent 
     self.centralWidget = QtGui.QWidget() 
     self.setCentralWidget(self.centralWidget) 
     self.mainHBOX_param_scene = QtGui.QHBoxLayout() 
     self.Button_Run = QtGui.QPushButton('Run') 
     self.mainHBOX_param_scene.addWidget(self.Button_Run) 
     self.centralWidget.setLayout(self.mainHBOX_param_scene) 

     self.worker = maclass() 
     self.Button_Run.clicked.connect(self.start) 

    def start(self): 
     for k in range(5): 
      self.worker.start(20) 



def main(): 
    app = QtGui.QApplication(sys.argv) 
    ex = SurfViewer(app) 
    ex.show() 
    sys.exit(app.exec_()) 


if __name__ == '__main__': 
    main() 

Большое спасибо людям, которые помогли мне.

3

Необходимо, чтобы рабочий был отделен от пользовательского интерфейса. Следующее работает отлично. Если вы хотите изменить переменные в maclass, вы все равно можете делать это снаружи.

import multiprocessing 
from PyQt4 import QtGui 
import sys 

class maclass(): 

    def __init__(self,): 
     pass 

    def start(self): 
     for i in range(5): 
      p = multiprocessing.Process(target=self.mp_worker , args=(i,)) 
      p.start() 

    def mp_worker(self,a): 
     print('a:' +str(a)) 
     return 


class SurfViewer(QtGui.QMainWindow): 
    def __init__(self, parent=None): 
     super(SurfViewer, self).__init__() 
     self.parent = parent 
     self.centralWidget = QtGui.QWidget() 
     self.setCentralWidget(self.centralWidget) 
     self.mainHBOX_param_scene = QtGui.QHBoxLayout() 
     self.Button_Run = QtGui.QPushButton('Run') 
     self.mainHBOX_param_scene.addWidget(self.Button_Run) 
     self.centralWidget.setLayout(self.mainHBOX_param_scene) 

     self.worker = maclass() 
     self.Button_Run.clicked.connect(self.start) 

    def start(self): 
     self.worker.start() 


def main(): 
    app = QtGui.QApplication(sys.argv) 
    ex = SurfViewer(app) 
    ex.show() 
    sys.exit(app.exec_()) 


if __name__ == '__main__': 
    main() 
+0

Я попробую это, и я вернусь, чтобы поделиться, если это сработает. Спасибо. – ymmx

Смежные вопросы