Python使用ProcessPoolExecutor多进程时实现Tkinter进度实时更新问题
Tkinter结合ProcessPoolExecutor实现多进程进度实时展示解决方案
核心问题原因
你提供的代码使用ProcessPoolExecutor不生效的核心原因如下:
- Windows系统下Python多进程默认采用
spawn启动模式,提交给进程池的可调用对象必须支持pickle序列化,原代码中work和save_values是定义在start_processing方法内的嵌套函数,无法被序列化,子进程无法正常接收并执行任务 - 原代码多进程同时写入同一个txt文件时没有加锁,会出现写入内容错乱的问题
修复后可运行代码
import concurrent.futures import tkinter import tkinter.ttk import multiprocessing import random import time # 把内部函数移到全局作用域,支持序列化 def save_values(my_values, write_lock): # 加锁避免多进程写入冲突 with write_lock: with open(f"example.txt", "a") as file: for v in my_values: file.write(str(v)) file.write(" ") file.write("\n") def work(my_values, my_queue, write_lock): my_progress = 0 step = 100 / len(my_values) updated_values = [] for v in my_values: time.sleep(0.5) updated_values.append(v + 1) my_progress += step my_queue.put(my_progress) save_values(updated_values, write_lock) class App: def __init__(self, root): self.root = root # 新增多进程写入锁 self.write_lock = multiprocessing.Lock() self.processes = 5 self.percentage = [] self.changing_labels = [] self.queues = [] self.values = [] for i in range(self.processes): temp_percentage = tkinter.StringVar() temp_percentage.set("0 %") self.percentage.append(temp_percentage) temp_changing_label = tkinter.Label(self.root, textvariable=temp_percentage) temp_changing_label.pack() self.changing_labels.append(temp_changing_label) self.queues.append(multiprocessing.Queue()) temp_value = [] for ii in range(12): temp_value.append(random.randrange(10)) self.values.append(temp_value.copy()) self.start_processing() def start_processing(self): with concurrent.futures.ProcessPoolExecutor() as executor: results = [executor.submit(work, self.values[i], self.queues[i], self.write_lock) for i in range(self.processes)] while True: results_done = [result.done() for result in results] if False in results_done: for i in range(self.processes): if not results_done[i]: if not self.queues[i].empty(): temp_queue = self.queues[i].get() self.percentage[i].set(f"{temp_queue:.2f} %") else: self.percentage[i].set("100 %") self.root.update() else: break self.root.destroy() def main(): root = tkinter.Tk() my_app = App(root) root.mainloop() if __name__ == "__main__": main()
关键修改说明
- 将原本嵌套在方法内的
work、save_values函数移到全局作用域,满足多进程序列化要求 - 新增
multiprocessing.Lock作为多进程写入文件的锁,避免文件内容错乱 - 未修改原代码的核心逻辑和
main函数结构,符合你的需求
内容的提问来源于stack exchange,提问作者Kounabi
相关产品推荐
相关产品推荐

