Home > Blockchain >  How to solve Problem with Multiprocessing in Tkinter?
How to solve Problem with Multiprocessing in Tkinter?

Time:11-06

Over here I am using multiprocessing to run multiple algorithms in tkinter. At first I tried using threading, but it can't work properly in my program. Below is an idea of my program workflow, it works something like this, but just different functions:

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()

The error produced is this:

TypeError: cannot pickle '_tkinter.tkapp' object

Anybody knows how to fix this?? thanks in advance!

CodePudding user response:

Here is an example of how to communicate with other processes if using multiprocessing (explanation is in comments, time.sleep is used just for the example because otherwise those loops will complete in a few microseconds):

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()

Useful:

See also:
I strongly advise against using wildcard (*) when importing something, You should either import what You need, e.g. from module import Class1, func_1, var_2 and so on or import the whole module: import module then You can also use an alias: import module as md or sth like that, the point is that don't import everything unless You actually know what You are doing; name clashes are the issue.

I strongly suggest following PEP 8 - Style Guide for Python Code. Function and variable names should be in snake_case, class names in CapitalCase. Don't have space around = if it is used as a part of keyword argument (func(arg='value')) but have space around = if it is used for assigning a value (variable = 'some value'). Have space around operators ( -/ etc.: value = x y(except here value = x y)). Have two blank lines around function and class declarations. Object method definitions have one blank line around them.

  • Related