【发布时间】:2021-10-22 11:54:48
【问题描述】:
我在文件 my_app.py 中有一个 tkinter GUI,在另一个文件 my_model.py 中有一个模型。该模型使用多处理进行一些计算。 MyModel 有一个外部循环,它在多处理之外。这个外部循环给出了程序中的步骤名称,所以我想使用这个名称来更新 GUI 中的标签。这样用户就可以看到当前状态。但是,当单击“运行”按钮时,GUI 冻结并且没有响应。只有当多处理完成后,才能再次使用 GUI,并且标签只显示最后一个(“名称 2”)。你能帮帮我吗?
谢谢。
我在 Windows 系统上使用 Python 3.8.10。
# 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}')
【问题讨论】:
-
_loop_with_mp的单次运行需要多长时间?还有Name 2没有Name 1显示的原因是因为代码执行不会回到tkinter的主循环,所以它不能自我更新。尝试使用tkinter循环重写 for 循环,例如 this -
MyModel 有一个在多处理之外的外部循环。我想这就是问题所在。如果主循环中的循环未完成,则主循环将无法继续,因此您的 GUI 将冻结。
标签: tkinter multiprocessing python-3.8