【问题标题】:Creating a Process object whose function is from another Class [Causes Error]创建一个 Process 对象,其功能来自另一个类 [导致错误]
【发布时间】:2021-01-18 06:55:09
【问题描述】:

我会尽我所能解释我的问题,请我真的需要你的帮助,尤其是对 Python 多处理专家的人,因为我喜欢多处理和我只是一个初学者学习。

def __handleDoubleClick(self,item):

        self.tmx_window.show()

        processes = []

        #self.tmx_window.fill_table(item.text(),self.language_code,self.xml_filepath.text())
        process_ft = Process(target=self.tmx_window.fill_table, args=(item.text(),self.language_code,self.xml_filepath.text()))
        processes.append(process_ft)
        process_ft.start()


        for process in processes:
            process.join()
        

现在我在这里有一个函数 (__handleDoubleClick),当你从我的 PYQT5 GUI 中双击一个小部件时,这个函数只是做一些事情,你可以在这里看到这行代码 self.tmx_window.show() 这显示了 我拥有的第二个 GUI。如果您对self.tmx_window 对象感到好奇,这是它的类,它只是继承了一个类QMainWindow 和Ui_TmxWindow,Ui_TmxWindow 来自QT Designer 生成的.py 文件。

class TmxWindow(QMainWindow,Ui_TmxWindow):
    def __init__(self):
        super().__init__()

        # Set up the user interface from Designer.
        self.setupUi(self)

你也可以再次看到,我这里有一个被调用的函数,就是这段代码。

#self.tmx_window.fill_table(item.text(),self.language_code,self.xml_filepath.text())

现在我已经将它注释掉了,我想让它成为一个 Process 对象,因为我想应用 multiprocessing 并且我需要它在未来与其他进程一起运行......现在作为你可以看到我已经应用了这个

process_ft = Process(target=self.tmx_window.fill_table, args=(item.text(),self.language_code,self.xml_filepath.text()))
processes.append(process_ft)
process_ft.start()


for process in processes:
    process.join()

目标的值有一个函数是self.tmx_window.fill_table,你可以看到这个函数来自另一个类,我从中创建了一个对象,你可以看到那个对象是@ 987654334@。现在不应用多处理一切正常,因为我正确调用了函数......但是当我应用多处理时,会出现此错误。顺便说一句,您会从错误中看到 "TmxWindow object",TmxWindow 是我所指的函数所属的类

Traceback (most recent call last):
  File "main.py", line 127, in __handleDoubleClick
    process_ft.start()
  File "C:\Users\LENOVO\.conda\envs\USA24\lib\multiprocessing\process.py", line 121, in start
    self._popen = self._Popen(self)
  File "C:\Users\LENOVO\.conda\envs\USA24\lib\multiprocessing\context.py", line 224, in _Popen
    return _default_context.get_context().Process._Popen(process_obj)
  File "C:\Users\LENOVO\.conda\envs\USA24\lib\multiprocessing\context.py", line 327, in _Popen
    return Popen(process_obj)
  File "C:\Users\LENOVO\.conda\envs\USA24\lib\multiprocessing\popen_spawn_win32.py", line 93, in __init__
    reduction.dump(process_obj, to_child)
  File "C:\Users\LENOVO\.conda\envs\USA24\lib\multiprocessing\reduction.py", line 60, in dump
    ForkingPickler(file, protocol).dump(obj)
TypeError: cannot pickle 'TmxWindow' object
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Users\LENOVO\.conda\envs\USA24\lib\multiprocessing\spawn.py", line 116, in spawn_main
    exitcode = _main(fd, parent_sentinel)
  File "C:\Users\LENOVO\.conda\envs\USA24\lib\multiprocessing\spawn.py", line 126, in _main
    self = reduction.pickle.load(from_parent)
EOFError: Ran out of input

现在我想尝试用 Threading 做同样的事情,我尝试了这个而不是 Process 并且它成功了!我熟悉线程和进程的区别,并且根据我读过的内容,线程在内存上共享,而进程不会导致它们有自己的(如果我错了,请纠正我)所以这就是我想应用多处理的原因而不是多线程。

所以问题是我担心的是我提供的错误......以及为什么它适用于 Threading 而不是 Process 。我觉得有很多我不了解的东西 MultiProcessing 我只是好奇我的意思是我只是遵循它并为 Process 对象提供了一个函数,该函数来自一个不同的类,我创建了一个对象的实例与...所以有人可以帮助我... Pleaaaseee。谢谢!

#self.tmx_window.fill_table(item.text(),self.language_code,self.xml_filepath.text())
thread_ft = threading.Thread(target=self.tmx_window.fill_table,args=[item.text(),self.language_code,self.xml_filepath.text()])
threads.append(thread_ft)
thread_ft.start()

【问题讨论】:

  • self.tmx_window.fill_table() 做什么?它是否访问项目视图(可能是 QTableView 或 QTableWidget)来创建/编辑其项目?
  • 是的,它从 QTableWidget self.tmx_table.setRowCount(4) 中添加了一些行,之后我还有另一个功能,但它只是处理一些数据并输出一个 .csv 文件
  • 目前它只有 4 行,但很快我将根据列表中的特定len() 添加更多内容,所以是的......我很好奇它为什么会出现这个错误 :( 和Threading 有效
  • 为了将来参考,一个小建议:请避免不必要的“聊天”俚语(“所以让我们进入正题”、笑脸、“pleeeeasee”、大量省略号等)。正如tour(你应该接受的)报告的那样:«这个网站就是为了得到答案。这不是一个讨论论坛。没有闲聊。»。虽然仁慈显然不受欢迎(主要是在行为上),但其他任何事情通常都被视为噪音,尤其是对于使用搜索引擎寻找答案的人来说,因为他们通常对直接答案感兴趣,而不是问候或滑稽的面孔。
  • 好吧好吧,你是对的!谢谢!

标签: python-3.x user-interface multiprocessing pyqt5 python-multithreading


【解决方案1】:

需要考虑的重要方面是不允许从除主 Qt 线程之外的任何外部线程访问 GUI 元素(包括创建新元素)。

使用多处理时,每个进程都有自己的线程(我简化了很多,请注意),所以如果您使用多处理,您基本上也使用不同的线程。此外,python 中处理之间的通信是通过 pickling 完成的(这对 Qt 对象不太适用)。

虽然在某些情况下从其他线程访问 UI 元素可能可以工作,但这通常只是巧合,因为当前的硬件/软件配置允许这些线程同步工作,因为它们可能非常敏感并且他们的通信队列不受其他事件的困扰。但是,这又是一个巧合。我很确定在其他情况下(慢速 CPU、其他并发进程等),即使使用线程,您的代码也不会工作。

因此,唯一安全的解决方案是使用线程,但只要您需要以任何方式访问 /strong> 带有 UI 元素。这意味着您必须使用 QThread 子类(因为它继承自 QObject,它提供信号/插槽机制),在那里进行“处理”并使用您的自定义信号与主 Qt 线程通信,因此将连接到实际更新您的项目视图的函数。

【讨论】:

  • 谢谢您的回答...所以多处理不在图表之列,我想我应该使用线程...请问您的意思是什么但只能与Qt的信号和槽
  • 您需要创建通常称为“Worker”的线程,它是 QThread 的自定义子类。在该子类中,您可以根据需要创建自己的自定义信号,然后创建一个 run() 方法来完成所有处理;当该处理完成时,发出将与主线程通信的信号“改变了”。您显然需要在对该对象调用start() 之前将该信号连接到适当的函数以实际启动它。寻找“QThread”和“worker”相关的问答,即使在 StackOverflow 上你也会发现很多结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-30
  • 1970-01-01
  • 2014-06-13
  • 2018-10-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多