I have a tkinter GUI in a file my_app.py and a model in another file my_model.py. The model does some calculations with multiprocessing. And MyModel has an outer loop which is outside multiprocessing. This outer loop gives the step names in the program, so I want to use this name to update a label in the GUI. So that user can see the current status. However, when the "Run" button is clicked, the GUI freezes and not responding. Only when multiprocessing finishes, can the GUI be used again, and the label just shows the last one ("Name 2"). Could you please help me?
Thanks.
I am using Python 3.8.10 on Windows system.
# my_app.py
import tkinter as tk
from mp_model import MyModel
class MyApp:
def __init__(self):
self._root = tk.Tk()
self.status = tk.StringVar()
self.status.set('Status')
self.label = tk.Label(self._root, textvariable=self.status)
self.btn = tk.Button(self._root, text='Run', command=self.run_model)
self.label.pack()
self.btn.pack()
def run(self):
self._root.mainloop()
def run_model(self):
model = MyModel(status_var=self.status)
model.run()
if __name__ == '__main__':
app = MyApp()
app.run()
# my_model.py
from multiprocessing import Pool
import time
from timeit import default_timer as timer
import multiprocessing as mp
import pandas as pd
def func_for_mp(name: str, ds_value: pd.Series) -> pd.Series:
print(f'Doing {name}.')
res_chunk = ds_value * 2.
time.sleep(2)
return res_chunk
class MyModel:
def __init__(self, status_var=None):
self.status_var = status_var
def run(self):
self._outer_loop()
def _outer_loop(self):
names = ['Name 1', 'Name 2']
for name in names:
self.status_var.set(name)
self._loop_with_mp(name)
def _loop_with_mp(self, name: str):
all_values = pd.Series(range(35))
n_cpu = mp.cpu_count()
chunk_size = int(len(all_values) / n_cpu) + 1
ds_chunks = [
all_values.iloc[i:i+chunk_size] for i in range(0, len(all_values), chunk_size)
]
start = timer()
with Pool(processes=n_cpu) as pool:
args = [(name, ds_chunk) for ds_chunk in ds_chunks]
results = pool.starmap(func_for_mp, args)
end = timer()
print(f'Total elapsed time: {end - start}')