无法在 Windows 的多处理环境中“pickle”Tkinter 对象

2024-04-29

我正在尝试创建一个应用程序,其中 Tkinter GUI 由不断获取数据的其他对象更新。我在使用多线程时遇到问题,因此我决定尝试使用多处理模块。

我发现您无法在其中运行 Tkinter 窗口multiprocessing.Process,这是最小的示例:

import Tkinter as tk
import multiprocessing

class Subprocess(multiprocessing.Process):
    def __init__(self):
        multiprocessing.Process.__init__(self)
        self.root = tk.Tk()
    #

    def run(self):
        self.root.mainloop()
    #

    def stop(self):
        self.root.destroy()
        self.terminate()


if __name__ == '__main__':
        process = Subprocess()
        process.start()
        print "I got around the global interpreter lock"
        raw_input()
        print "exiting"
        process.stop()

我期望发生的是弹出一个 Tk 窗口,并在终端中显示“我绕过了全局解释器锁”。我在 ubuntu linux 上测试了这个,它工作得很好,但是当我切换到 Windows 7(我正在开发我的应用程序)时,它失败了,给了我错误:

Traceback (most recent call last):
  File "C:\pathtoscript\multiprocessing_test.py", line 21, in <module>
    process.start()
  File "C:\Python27\lib\multiprocessing\process.py", line 130, in start
    self._popen = Popen(self)
  File "C:\Python27\lib\multiprocessing\forking.py", line 277, in __init__
    dump(process_obj, to_child, HIGHEST_PROTOCOL)
  File "C:\Python27\lib\multiprocessing\forking.py", line 199, in dump
    ForkingPickler(file, protocol).dump(obj)
  File "C:\Python27\lib\pickle.py", line 224, in dump
    self.save(obj)
  File "C:\Python27\lib\pickle.py", line 331, in save
    self.save_reduce(obj=obj, *rv)
  File "C:\Python27\lib\pickle.py", line 419, in save_reduce
    save(state)
  File "C:\Python27\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python27\lib\pickle.py", line 649, in save_dict
    self._batch_setitems(obj.iteritems())
  File "C:\Python27\lib\pickle.py", line 681, in _batch_setitems
    save(v)
  File "C:\Python27\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python27\lib\pickle.py", line 725, in save_inst
    save(stuff)
  File "C:\Python27\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python27\lib\pickle.py", line 649, in save_dict
    self._batch_setitems(obj.iteritems())
  File "C:\Python27\lib\pickle.py", line 681, in _batch_setitems
    save(v)
  File "C:\Python27\lib\pickle.py", line 313, in save
    (t.__name__, obj))
PicklingError: Can't pickle 'tkapp' object: <tkapp object at 0x02BD3D08>

有谁知道这个问题的解决方法?我觉得奇怪的是,这在 Linux 上有效,但在 Windows 上无效。


这是一个简单的修复 - 只需创建tkapp子进程中的对象,而不是父进程中的对象:

import Tkinter as tk
import multiprocessing
from Queue import Empty

class Subprocess(multiprocessing.Process):
    def __init__(self):
        multiprocessing.Process.__init__(self)
        self.queue = multiprocessing.Queue()
    #

    def run(self):
        self.root = tk.Tk()
        self.root.after(100, self._check_queue) # Check the queue every 100ms
        self.root.mainloop()

    def _check_queue(self):
        try:
            out = self.queue.get_nowait()
            if out == 'stop':
                self.do_stop()
                return
            # Could check for other commands here, too
        except Empty:
            pass
        self.root.after(100, self._check_queue)

    def stop(self):
        self.queue.put('stop')

    def do_stop(self):
        self.root.destroy()


if __name__ == '__main__':
    process = Subprocess()
    process.start()
    print "I got around the global interpreter lock"
    raw_input()
    print "exiting"
    process.stop()

试图创建tkapp在父母身上,然后在孩子身上开始,这不是一个可行的解决方案。唯一棘手的部分是你需要使用Queue告诉父进程停止子进程中的循环。

另外,就其价值而言,在 Linux 上运行原始代码实际上会让我的解释器崩溃:

XIO:  fatal IO error 11 (Resource temporarily unavailable) on X server ":0"
      after 87 requests (87 known processed) with 0 events remaining.
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
python: ../../src/xcb_io.c:274: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

无法在 Windows 的多处理环境中“pickle”Tkinter 对象 的相关文章

随机推荐