Python 使用tkinter按钮终止多进程池

Python 使用tkinter按钮终止多进程池,python,multithreading,tkinter,multiprocessing,Python,Multithreading,Tkinter,Multiprocessing,我正在构建一个应用程序,根据用户输入的内容进行数千(可能数百万)计算。因为这些计算可能需要很长时间,所以我想使用Python的多处理模块。这是我的困境;我想设置一个带有取消按钮的tkinter窗口,以停止在我使用Pool设置的处理器中运行的计算。我尝试使用线程来允许弹出窗口运行,但在运行代码时发生了一些有趣的事情 当我按下“开始”按钮时,游泳池开始按预期运行。然而,我的弹出窗口不会显示,即使它在自己的线程上。更奇怪的是,当我告诉我的IDE(PyCharm)停止程序时,弹出窗口显示,计算仍在运行,

我正在构建一个应用程序,根据用户输入的内容进行数千(可能数百万)计算。因为这些计算可能需要很长时间,所以我想使用Python的多处理模块。这是我的困境;我想设置一个带有取消按钮的tkinter窗口,以停止在我使用Pool设置的处理器中运行的计算。我尝试使用线程来允许弹出窗口运行,但在运行代码时发生了一些有趣的事情

当我按下“开始”按钮时,游泳池开始按预期运行。然而,我的弹出窗口不会显示,即使它在自己的线程上。更奇怪的是,当我告诉我的IDE(PyCharm)停止程序时,弹出窗口显示,计算仍在运行,直到我从弹出窗口按下“退出”按钮,或者完全终止程序

所以我的问题是:为什么我的弹出窗口即使在自己的线程上也不会显示?我是否正确使用了多处理模块?还是问题完全不同

import tkinter as tk
from tkinter import ttk
import random
import threading
import time
from multiprocessing import Pool

def f(x):
    print(x*x)
    time.sleep(random.randrange(1,5))  # simulates long calculations
    # Extra math stuff here...

def processor():
    global calc
    calc = Pool(4)
    calc.map(f, [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30])
    print("Done")

def calculation_start():
    p = threading.Thread(target=progress_window)  # Thread to open a new window for the user to cancel a calculation
    p.start()
    processor()  # Calls the function to run the calculations

def progress_window():
    # This is the window that pops up to let a user cancel a calculation.
    popup = tk.Toplevel()
    endButton = ttk.Button(popup, text="End", command=lambda :(calc.terminate()))
    endButton.pack()


master = tk.Tk()

startButton = ttk.Button(master, text="Start", command=calculation_start)
startButton.pack()

tk.mainloop()
编辑: 我尝试将
处理器
函数切换到线程,而不是
进程窗口
函数

def calculation_start():
    p = threading.Thread(target=processor)  # Thread for the function to run the calculations
    p.start()
    progress_window()  # Open a new window for the user to cancel a calculation
我的弹出窗口出现,按下“结束”按钮时,它看起来会停止处理器,但它不会继续超过该点。就像它卡在
processor()函数中的
calc.map(f[1,2,3,…]

来自文档:

def calculation_start():
    p = threading.Thread(target=processor)  # Thread for the function to run the calculations
    p.start()
    progress_window()  # Open a new window for the user to cancel a calculation
它将阻塞,直到结果就绪

这意味着,是的,工作正在其他线程上完成,但是主线程(调用
map
的线程)在其他线程完成之前不会执行任何其他操作。您希望使用并(对于长时间运行的交互式进程)提供一个回调,以便在池完成时执行什么操作(可能隐藏弹出窗口)


如果希望程序只显示弹出窗口然后退出,则需要使用
map\u async
返回的。在空闲后使用
设置空闲处理程序(请参阅并记住,每次调用后都需要手动重新添加处理程序)。在每次空闲调用后,可以调用
AsyncResult.ready()
AsyncResult.get()
查看池是否已完成。一旦完成,您就可以安全地处理结果并退出。

尝试在
master=tk.tk()之前添加
如果uuuu name\uuuuu=='\uuu main\uuuu':
并缩进它和后面的其他行。@martineau感谢您的建议,但它仍然遇到相同的问题。1.启动进程池一次2.在这种情况下不要使用线程3.要在池完成给定任务时收到通知,请将更新GUI的回调传递到
池。应用异步
池.map_async
我为
map_async
关闭了
map
,它立即运行回调并在回调后继续运行代码。但是,它不会等待池完成或通过代码继续终止(回拨也是如此。它一开始就被调用)。它应该这样做吗?有没有办法让它等到完成或终止?更新后的答案会处理您的跑步然后退出场景。