使用tkinter按钮杀死多进程池 [英] Killing a multiprocess pool using a tkinter button

查看:196
本文介绍了使用tkinter按钮杀死多进程池的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm building an application that does thousands (possibly millions) of calculations based off of what the user inputs. Because these calculations can take a long time, I want to use Python's multiprocessing module. Here is my dilemma; I want to set up a tkinter window with a cancel button to stop the calculations running throughout the processors I set up using Pool. I tried using threads to allow the popup window to run, but some funny things happen when I run the code.

当我按下开始"按钮时,泳池开始按预期运行.但是,即使弹出窗口位于其自己的线程上,也不会显示.甚至更奇怪的是,当我告诉我的IDE(PyCharm)停止程序时,将显示弹出窗口,并且计算仍在运行,直到我从弹出窗口中按退出"按钮或完全终止该程序为止.

When I press the 'start' button, the Pool starts going as expected. However, my popup window does not show even though it is on its own thread. Even weirder, when I tell my IDE (PyCharm) to stop the program, the popup window shows and the calculations are still running until I either press the 'exit' button from the popup window, or kill the program altogether.

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

So my questions are: Why won't my popup window show even though it is on its own thread? Am I utilizing the multiprocessing module correctly? Or is the problem something totally different?

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

我尝试将processor函数切换为线程而不是progress_window函数.

I tried switching the processor function to a thread instead of the progress_window function.

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,...]上一样.

My popup window appears and the 'end' button looks like it stops the processor when pressed, but it never continues past that point. It's like it's stuck at calc.map(f, [1,2,3,...] in the processor() function.

推荐答案

来自 Pool.map 文档:

它会阻塞直到结果准备就绪.

It blocks until the result is ready.

这意味着,是的,工作正在其他线程上完成,但是主线程(调用map的那个线程)在其他线程完成之前不会执行任何其他操作.您要使用 map_async 和(对于长时间运行的交互式过程),提供一个回调,以告知完成池后的操作(可能隐藏弹出窗口).

That means that, yes, the work is being done on other threads, but the main thread (the one calling map) will not execute anything else until the other threads are complete. You want to use map_async and (for a long-running, interactive process), provide a callback for what to do when the pool is finished (probably hide the pop-up).

如果要让程序仅显示弹出窗口然后退出,则要使用 tkinter通用窗口小部件方法,请记住,您需要在每次调用后手动重新添加处理程序).在每个空闲呼叫之后,您可以呼叫AsyncResult.ready()AsyncResult.get(<timeout>)来查看池是否已完成.完成后,您可以安全地处理结果并退出.

If you want your program to simply show the pop-up then exit, you want to use the AsyncResult returned by map_async. Set up an idle handler using after_idle (See tkinter universal widget methods and remember you'll need to manually re-add the handler after every call). After each idle call, you could call either AsyncResult.ready() or AsyncResult.get(<timeout>) to see if the pool has completed. Once it's finished, you're safe to process the results and exit.

这篇关于使用tkinter按钮杀死多进程池的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆