【问题标题】:Tkinter with multiprocessing: OSError [Errno 22] Invalid argument具有多处理功能的 Tkinter:OSError [Errno 22] 无效参数
【发布时间】:2021-05-24 06:54:02
【问题描述】:

我正在尝试向我的 tkinter 应用程序添加多处理,但我一直遇到错误问题:TypeError: cannot pickle '_tkinter.tkapp' object。我查看了question here 中提出的解决方案,并尝试实现我自己的版本,这似乎解决了这个特定错误,但现在我改为使用常量OSError: [Errno 22] Invalid argument:

我希望代码做的是在后台执行一些计算,并将该计算的结果放入队列(这里只是整数,但在实际代码中将是 Numpy 数组)。 GUI 应用程序然后向用户显示一些统计数据和结果。

from multiprocessing import Process, Queue
from queue import Empty
import tkinter as tk
from tkinter import Tk

class FooUI(Process):
    def __init__(self, q: Queue):
        super().__init__(target=self, args=(q,))
        self.queue = q
        self.duh = []
        self.root = Tk()
        self._create_interface()
        self.root.after(100, self._check_queue)
        self.root.mainloop()
        
    def _check_queue(self):
        try:
            out = self.queue.get_nowait()
            if out:
                self.duh.append(out)
                print(self.duh)
                return
        except Empty:
            pass
        self.root.after(100, self._check_queue) 
    
    def _create_interface(self):
        self.root.geometry("100x100")
        b = tk.Button(self.root, text='Start', command=self.calc)
        b.grid(row=0, column=0)
    
    def calc(self):
        p = Process(target=do_calc)
        p.start()     
        
def do_calc(q: Queue):
    for i in range(20):
        q.put(i**2)


If __name__ == '__main__':
    q = Queue()
    f = FooUI(q)
    f.start()

这是回溯:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Users\cherp2\AppData\Local\Programs\Python\Python38\lib\multiprocessing\spawn.py", line 116, in spawn_main
    exitcode = _main(fd, parent_sentinel)
  File "C:\Users\cherp2\AppData\Local\Programs\Python\Python38\lib\multiprocessing\spawn.py", line 125, in _main
    prepare(preparation_data)
  File "C:\Users\cherp2\AppData\Local\Programs\Python\Python38\lib\multiprocessing\spawn.py", line 236, in prepare
    _fixup_main_from_path(data['init_main_from_path'])
  File "C:\Users\cherp2\AppData\Local\Programs\Python\Python38\lib\multiprocessing\spawn.py", line 287, in _fixup_main_from_path
    main_content = runpy.run_path(main_path,
  File "C:\Users\cherp2\AppData\Local\Programs\Python\Python38\lib\runpy.py", line 264, in run_path
    code, fname = _get_code_from_file(run_name, path_name)
  File "C:\Users\cherp2\AppData\Local\Programs\Python\Python38\lib\runpy.py", line 234, in _get_code_from_file
    with io.open_code(decoded_path) as f:
OSError: [Errno 22] Invalid argument: 'C:\\python\\block_model_variable_imputer\\<input>'
Traceback (most recent call last):
  File "<input>", line 3, in <module>
  File "C:\Users\cherp2\AppData\Local\Programs\Python\Python38\lib\multiprocessing\process.py", line 121, in start
    self._popen = self._Popen(self)
  File "C:\Users\cherp2\AppData\Local\Programs\Python\Python38\lib\multiprocessing\context.py", line 224, in _Popen
    return _default_context.get_context().Process._Popen(process_obj)
  File "C:\Users\cherp2\AppData\Local\Programs\Python\Python38\lib\multiprocessing\context.py", line 327, in _Popen
    return Popen(process_obj)
  File "C:\Users\cherp2\AppData\Local\Programs\Python\Python38\lib\multiprocessing\popen_spawn_win32.py", line 93, in __init__
    reduction.dump(process_obj, to_child)
  File "C:\Users\cherp2\AppData\Local\Programs\Python\Python38\lib\multiprocessing\reduction.py", line 60, in dump
    ForkingPickler(file, protocol).dump(obj)
TypeError: cannot pickle '_tkinter.tkapp' object
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Users\cherp2\AppData\Local\Programs\Python\Python38\lib\multiprocessing\spawn.py", line 116, in spawn_main
    exitcode = _main(fd, parent_sentinel)
  File "C:\Users\cherp2\AppData\Local\Programs\Python\Python38\lib\multiprocessing\spawn.py", line 125, in _main
    prepare(preparation_data)
  File "C:\Users\cherp2\AppData\Local\Programs\Python\Python38\lib\multiprocessing\spawn.py", line 236, in prepare
    _fixup_main_from_path(data['init_main_from_path'])
  File "C:\Users\cherp2\AppData\Local\Programs\Python\Python38\lib\multiprocessing\spawn.py", line 287, in _fixup_main_from_path
    main_content = runpy.run_path(main_path,
  File "C:\Users\cherp2\AppData\Local\Programs\Python\Python38\lib\runpy.py", line 264, in run_path
    code, fname = _get_code_from_file(run_name, path_name)
  File "C:\Users\cherp2\AppData\Local\Programs\Python\Python38\lib\runpy.py", line 234, in _get_code_from_file
    with io.open_code(decoded_path) as f:
OSError: [Errno 22] Invalid argument: 'C:\\python\\block_model_variable_imputer\\<input>'

我已经尝试了一段时间来让它工作。任何帮助将不胜感激!

【问题讨论】:

  • 为什么需要多处理?为什么不能只使用线程?您拥有的代码创建了第二个 UI 将运行的进程,然后是第三个进程来进行计算,而主进程显然刚刚退出。您是否尝试过简单的FooUI(Queue())
  • @TimRoberts,我需要多处理来并行运行多个计算,但如果我只是尝试从运行 tkinter 实例的主进程生成计算进程,则会导致此错误:TypeError: cannot pickle '_tkinter.tkapp' object。这样我可以避免这个 TypeError 但又出现了一个。
  • 我非常怀疑tkinter 是否支持多处理。在一个线程中创建的小部件无法与另一个线程中的小部件进行通信。
  • @CoolCloud,但是如果在另一个过程中我们没有小部件而是一些与 tkinter 完全无关的计算怎么办?还是不行吗?
  • 是的,应该没问题。所有 tkinter 的东西都应该在一个进程中。

标签: python tkinter multiprocessing


【解决方案1】:

您以错误的方式执行Process() 的子类。您需要覆盖 run() 方法,而不是传递 target 选项。

from multiprocessing import Process, Queue
from queue import Empty
import tkinter as tk

class FooUI(Process):
    def __init__(self, q: Queue):
        super().__init__() # don't pass target and args options
        self.queue = q
        self.duh = []
    
    # override run() method and create the Tk() inside the function
    def run(self):
        self.root = tk.Tk()
        self._create_interface()
        self.root.after(100, self._check_queue)
        self.root.mainloop()
        
    def _check_queue(self):
        try:
            out = self.queue.get_nowait()
            if out:
                self.duh.append(out)
                print(self.duh)
                #return
        except Empty:
            pass
        self.root.after(100, self._check_queue) 
    
    def _create_interface(self):
        self.root.geometry("100x100")
        b = tk.Button(self.root, text='Start', command=self.calc)
        b.grid(row=0, column=0)
    
    def calc(self):
        if self.queue.empty():
            self.duh.clear()
            p = Process(target=do_calc, args=[self.queue]) # pass self.queue to do_calc()
            p.start()     
        
def do_calc(q: Queue):
    for i in range(20):
        q.put(i**2)

if __name__ == '__main__':
    q = Queue()
    f = FooUI(q)
    f.start()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-13
    • 2019-04-27
    • 1970-01-01
    • 1970-01-01
    • 2018-10-05
    • 2018-05-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多