无法在我的PyQT5应用程序中使用joblib并行运行方法,

时间:2019-02-16 20:10:57

标签: python parallel-processing pyqt pyqt5 joblib

我对PyQT5并行编程非常陌生。我想在GUI中并行运行10种方法,但我使用的Joblib异常中止。

我得到TypeError: cannot unpack non-iterable function object。我尝试使用枚举器,但仍然中止。


我的错误消息:

joblib.externals.loky.process_executor._RemoteTraceback: 
"""
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/joblib/externals/loky/process_executor.py", line 418, in _process_worker
    r = call_item()
  File "/usr/local/lib/python3.7/site-packages/joblib/externals/loky/process_executor.py", line 272, in __call__
    return self.fn(*self.args, **self.kwargs)
  File "/usr/local/lib/python3.7/site-packages/joblib/_parallel_backends.py", line 567, in __call__
    return self.func(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/joblib/parallel.py", line 225, in __call__
    for func, args, kwargs in self.items]
  File "/usr/local/lib/python3.7/site-packages/joblib/parallel.py", line 225, in <listcomp>
    for func, args, kwargs in self.items]
TypeError: cannot unpack non-iterable function object
"""

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "job_parallel.py", line 73, in button_click_parallel
    Parallel(n_jobs=8)(delayed(command_list[i]()) for i in range(10))
  File "/usr/local/lib/python3.7/site-packages/joblib/parallel.py", line 934, in __call__
    self.retrieve()
  File "/usr/local/lib/python3.7/site-packages/joblib/parallel.py", line 833, in retrieve
    self._output.extend(job.get(timeout=self.timeout))
  File "/usr/local/lib/python3.7/site-packages/joblib/_parallel_backends.py", line 521, in wrap_future_result
    return future.result(timeout=timeout)
  File "/usr/local/Cellar/python/3.7.2/Frameworks/Python.framework/Versions/3.7/lib/python3.7/concurrent/futures/_base.py", line 432, in result
    return self.__get_result()
  File "/usr/local/Cellar/python/3.7.2/Frameworks/Python.framework/Versions/3.7/lib/python3.7/concurrent/futures/_base.py", line 384, in __get_result
    raise self._exception
TypeError: cannot unpack non-iterable function object
Abort trap: 6

我的代码:

#!/usr/bin/env python3

import sys
from PyQt5 import QtCore, QtWidgets
from joblib import Parallel, delayed
import threading


class Window(QtWidgets.QMainWindow):

    #uart_list = [1,2,3,4,5]

    def __init__(self):
        super(Window, self).__init__()

        self.x_size = 800
        self.y_size = 650
        self.setFixedSize(self.x_size, self.y_size)
        self.setWindowTitle("Test")

        buttons = list()

        self.button1 = QtWidgets.QPushButton("ONE", self)
        self.button1.move(100,100)
        buttons.append(self.button1)

        self.button2 = QtWidgets.QPushButton("TWO", self)
        self.button2.move(100,150)
        buttons.append(self.button2)

        for button in buttons:
            button.clicked.connect(self.button_click_parallel)

        self.show()

    def run_iot_uart1(self):
        print("Job 1")

    def run_iot_uart2(self):
        print("Job 2")

    def run_iot_uart3(self):
        print("Job 3")

    def run_iot_uart4(self):
        print("Job 4")

    def run_iot_uart5(self):
        print("Job 5")

    def run_iot_uart6(self):
        print("Job 6")

    def run_iot_uart7(self):
        print("Job 7")

    def run_iot_uart8(self):
        print("Job 8")

    def run_iot_uart9(self):
        print("Job 9")

    def run_iot_uart10(self):
        print("Job 10")


    def button_click_parallel(self): # Click any button, process all UART in parallel
        command_list=[self.run_iot_uart1, self.run_iot_uart2, self.run_iot_uart3,
                      self.run_iot_uart4, self.run_iot_uart5, self.run_iot_uart6,
                      self.run_iot_uart7, self.run_iot_uart8, self.run_iot_uart9,
                      self.run_iot_uart10]
        Parallel(n_jobs=10)(delayed(command_list[i]()) for i in range(10))
       sys.stdout.flush()

def run():
    QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True)
    app = QtWidgets.QApplication(sys.argv)
    GUI = Window()
    sys.exit(app.exec_())

run()

1 个答案:

答案 0 :(得分:1)

问题似乎出在您的Parallel设置中。我以前从未使用过此库,但是文档提供了以下示例,其中collect是一个函数。

Parallel(n_jobs=2)(
    delayed(collect)(i) 
    for i in range(5)
)

此处,函数被传递给delay,并且该函数的参数作为参数传递给该调用的结果。那是

delayed_function = delayed(function)
delayed_function(arg)

在示例代码中,您通过command_list[i]获取该函数,然后立即command_list[i]()对其进行调用,然后将该函数的 result (字符串)传递给{{ 1}}。

delayed

我认为您正在寻找的是

Parallel(n_jobs=10)(
    delayed(command_list[i]()) 
    for i in range(10)
)

无法腌制x

对您的代码进行更改后,我仍然收到以下错误-

Parallel(n_jobs=10)(
    delayed(command_list[i])()
    for i in range(10)
)

之所以会发生这种情况,是因为Parallel使用File "/usr/local/lib/python3.6/site-packages/joblib/parallel.py", line 183, in delayed pickle.dumps(function) TypeError: can't pickle Window objects (Python序列化格式)将函数和参数发送给执行程序。不幸的是,看起来pickle(可能还有其他Qt对象?)不可腌制。由于您的窗口方法需要访问QWindow,因此需要对其进行腌制。

解决方案是将这些方法a)移至可腌制的类,b)移至函数。下面是第二步。

self

运行此命令并按“ ONE”按钮,将得到以下输出。

#!/usr/bin/env python3

import sys
from PyQt5 import QtCore, QtWidgets
from joblib import Parallel, delayed
import threading

def run_iot_uart1():
    print("Job 1")

def run_iot_uart2():
    print("Job 2")

def run_iot_uart3():
    print("Job 3")

def run_iot_uart4():
    print("Job 4")

def run_iot_uart5():
    print("Job 5")

def run_iot_uart6():
    print("Job 6")

def run_iot_uart7():
    print("Job 7")

def run_iot_uart8():
    print("Job 8")

def run_iot_uart9():
    print("Job 9")

def run_iot_uart10():
    print("Job 10")


class Window(QtWidgets.QMainWindow):

    #uart_list = [1,2,3,4,5]

    def __init__(self):
        super(Window, self).__init__()

        self.x_size = 800
        self.y_size = 650
        self.setFixedSize(self.x_size, self.y_size)
        self.setWindowTitle("Test")

        buttons = list()

        self.button1 = QtWidgets.QPushButton("ONE", self)
        self.button1.move(100,100)
        buttons.append(self.button1)

        self.button2 = QtWidgets.QPushButton("TWO", self)
        self.button2.move(100,150)
        buttons.append(self.button2)

        for button in buttons:
            button.clicked.connect(self.button_click_parallel)

        self.show()

    def button_click_parallel(self): # Click any button, process all UART in parallel
        command_list=[run_iot_uart1, run_iot_uart2, run_iot_uart3,
                      run_iot_uart4, run_iot_uart5, run_iot_uart6,
                      run_iot_uart7, run_iot_uart8, run_iot_uart9,
                      run_iot_uart10]
        Parallel(n_jobs=10)(delayed(command_list[i])() for i in range(10))
        sys.stdout.flush()

def run():
    QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True)
    app = QtWidgets.QApplication(sys.argv)
    GUI = Window()
    sys.exit(app.exec_())

run()