如何解决 Tkinter 中的多处理问题?

Posted

技术标签:

【中文标题】如何解决 Tkinter 中的多处理问题?【英文标题】:How to solve Problem with Multiprocessing in Tkinter? 【发布时间】:2021-12-19 11:55:17 【问题描述】:

在这里,我使用多处理在 tkinter 中运行多种算法。起初我尝试使用线程,但它无法在我的程序中正常工作。下面是我的程序工作流程的一个想法,它的工作原理是这样的,但功能不同:

from tkinter import *
from multiprocessing import Process

def SquarFunc(Square):
    for i in range(1,1000):
        Square.set(str(i**2))

def CubeFunc(Cube):
    for i in range(1,1000):
        Cube.set(str(i**3))

if __name__ == "__main__":
    window= Tk()
    Square= StringVar()
    Cube= StringVar()
    window.geometry("500x500")
    A= Label(window, textvariable= Square)
    A.place(x=200, y=200)
    B= Label(window, textvariable= Cube)
    B.place(x=300, y=300)

    Squaring= Process(target=SquarFunc, args=(Square, ))
    Cubing= Process(target=CubeFunc, args=(Cube, ))
    Squaring.start()#Error originates here
    Cubing.start()
    Squaring.join()
    Cubing.join()
    window.mainloop()

产生的错误是这样的:

TypeError: cannot pickle '_tkinter.tkapp' object

有人知道如何解决这个问题吗?提前致谢!

【问题讨论】:

这个答案是否涵盖了您需要的内容:***.com/a/26835188/8382028 如果不是,您需要发布您的代码,而不仅仅是错误 @ViaTech 我已经阅读了那个链接..但我不太明白它的含义,而且它与我的程序有点不同..让我编辑我的帖子并输入代码..谢谢 @ViaTech 我已经发布了我的代码..你知道如何解决它吗? 提供minimal reproducible example而不是你的整个代码,无论如何,你不能在其他进程中使用tkinter,因为它不可腌制 @Matiiss 好的.... 【参考方案1】:

这是一个使用multiprocessing 时如何与其他进程通信的示例(解释在 cmets 中,time.sleep 仅用于示例,否则这些循环将在几微秒内完成):

from tkinter import Tk, StringVar, Label
from multiprocessing import Process, Manager
import time


def square_func(d, name):
    for i in range(1, 1000):
        # update data in the shared dict
        d[name] = i
        time.sleep(0.1)


def cube_func(d, name):
    for i in range(1, 1000):
        # update data in the shared dict
        d[name] = i
        time.sleep(0.1)


def update_string_vars(d, *variables):
    for var in variables:
        # get the value from shared dict
        value = d[str(var)]
        if value is not None:
            # set string var to the value
            var.set(str(value))
    # schedule this to run again
    window.after(100, update_string_vars, d, *variables)


# cleanup process upon closing the window in case 
# processes haven't finished
def terminate_processes(*processes):
    for p in processes:
        p.terminate()


if __name__ == "__main__":
    window = Tk()
    window.geometry("500x500")
    # bind the terminator to closing the window
    window.bind('<Destroy>', lambda _: terminate_processes(
            square_process, cube_process))

    square_var = StringVar()
    cube_var = StringVar()

    Label(window, text='Square:').pack()
    Label(window, textvariable=square_var).pack()

    Label(window, text='Cube:').pack()
    Label(window, textvariable=cube_var).pack()
    
    # create the manager to have a shared memory space
    manager = Manager()
    # shared dict with preset values as to not raise a KeyError
    process_dict = manager.dict(str(square_var): None, str(cube_var): None)

    square_process = Process(
        target=square_func, args=(process_dict, str(square_var))
    )
    cube_process = Process(
        target=cube_func, args=(process_dict, str(cube_var))
    )
    square_process.start()
    cube_process.start()
    
    # start the updater
    update_string_vars(process_dict, square_var, cube_var)

    window.mainloop()

有用:

Sharing state between processes shortly about tkinter and processes

另见: 我强烈建议不要在导入某些内容时使用通配符 (*),您应该导入您需要的内容,例如from module import Class1, func_1, var_2 等等或导入整个模块:import module 然后你也可以使用别名:import module as md 或类似的东西,关键是不要导入所有东西,除非你真的知道你在做什么;名称冲突是问题所在。

我强烈建议关注PEP 8 - Style Guide for Python Code。函数和变量名应该在snake_case,类名在CapitalCase。如果= 用作关键字参数的一部分(func(arg='value')),则不要在= 周围留有空格,但如果将= 用于分配值(variable = 'some value'),则在= 周围留有空格。在运算符周围留出空间(+-/ 等:value = x + y(此处除外value += x + y))。在函数和类声明周围有两个空行。对象方法定义周围有一个空行。

【讨论】:

非常感谢您的解释! 非常感谢您的指导,现在我终于可以在我的竞赛项目中成功实施了。。您介意可以分享一下您的电子邮件地址吗,以便我可以交流我的想法如果我以后有更多的困难,特别是在python编程方面。再次感谢你。

以上是关于如何解决 Tkinter 中的多处理问题?的主要内容,如果未能解决你的问题,请参考以下文章

使用继承正确扩展 tkinter 小部件

Tkinter:使用鼠标绘制矩形

Java 并发编程解析 | 如何正确理解Java领域中的多线程模型,主要用来解决什么问题?

Python Tkinter:如何让画布每帧更新多边形坐标? [解决了]

如何同时移动两个 tkinter 小部件但异步?

python tkinter 中的combobox如何添加字典?