你能解释一下,当作为一个单独的进程执行辅助函数时,我是如何防止python GUI冻结的吗?
我编写了一个python GUI,点击一个按钮,就可以通过多处理模块启动一个进程。我决定使用多处理而不是线程,因为我喜欢选择启动、暂停、恢复和终止进程。
不幸的是,当辅助进程运行时,GUI会冻结并失去响应,因此我无法按下“暂停”按钮。
图形用户界面的冻结问题在stackoverflow上报告过几次,但是这个问题似乎没有一个单一的来源,也没有一个统一的解决方案。因此我的问题不是重复的。
我目前完全不知道如何解决这个冰冻问题。到目前为止,我对解决方案的唯一猜测是为Tkinter使用一个名为mtTkinter的线程安全包装器,希望它也能帮助进行多处理。但它什么也没做。
也许需要在GUI和工作进程之间html" target="_blank">添加另一层。
欢迎提供任何建议、提示和解决方案。
最小代码:
import Tkinter as tk
import time
import multiprocessing
import psutil
def test_function():
print 'Test process starting.'
for i in range(11):
print "Test process running, step: ", i
time.sleep(1)
print 'Test process finished.'
class MainScreen(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title("CardZilla 0.1")
self.resizable(0, 0)
self.s_button = tk.Button(self, text="START", command=self.on_start)
self.p_button = tk.Button(self, text="PAUSE", state='disabled', command=self.on_pause)
self.s_button.pack(side=tk.LEFT)
self.p_button.pack(side=tk.LEFT)
def update_all(self): #updates button states
b_list= {self.s_button, self.p_button}
for b in b_list:
b.update()
def on_start(self):
if self.s_button["text"] == "RESUME":
self.s_button["text"] = "START"
self.p_button["text"] = "PAUSE"
self.ps.resume() #resume command for process
else:
str = 'test arg'
#queue = Queue()
p = multiprocessing.Process(None, test_function)
p.start()
self.ps = psutil.Process(p.pid) #getting pid of process, how to move self.ps under def __init__(self): ?
self.s_button["state"] = 'disabled'
self.p_button["state"] = 'normal'
self.update_all()
p.join() #ending process
self.s_button["state"] = 'normal'
self.p_button["state"] = 'disabled'
self.update_all()
def on_pause(self):
if self.p_button["text"] == "PAUSE":
print 'Pause button clicked.'
self.s_button["text"] = "RESUME"
self.s_button["state"] = 'normal'
self.p_button["text"] = "CANCEL"
self.update_all()
self.ps.suspend() #pausing command for process
else:
self.s_button["text"] = "START"
self.s_button["state"] = 'normal'
self.p_button["text"] = "PAUSE"
self.p_button["state"] = "disabled"
self.update_all()
self.ps.terminate() #good to terminate via psutils versus native multiprocessing interface?
if __name__ == '__main__':
ms = MainScreen()
ms.mainloop()
问题是,您正在调用p.join()
以等待进程在启动时退出函数:
p = multiprocessing.Process(None, test_function)
p.start()
self.ps = psutil.Process(p.pid) #getting pid of process, how to move self.ps under def __init__(self): ?
self.s_button["state"] = 'disabled'
self.p_button["state"] = 'normal'
self.update_all()
p.join() # this will block until `p` is complete
这样做可以防止控制返回到您的事件循环,直到进程退出,这意味着在发生这种情况和
on_start
退出之前,图形用户界面将没有响应。删除对加入
的调用,图形用户界面应该会被解除阻塞。
现在,这暴露了设计中的其他问题,因为您只想在流程完成后更新GUI。您可以使用
after
方法偶尔检查流程是否已完成。通过这种方式,事件循环基本上是未阻塞的,我们只是短暂地阻塞它,以查看流程是否已完成。如果有,我们会更新GUI按钮。如果没有,我们计划检查方法在0.5
秒内再次运行。
def check_proc(self):
if not self.p.is_alive():
# Process is done. Update the GUI
self.p.join()
self.s_button["state"] = 'normal'
self.p_button["state"] = 'disabled'
self.update_all()
else:
# Not done yet. Check again later.
self.after(500, self.check_proc)
def on_start(self):
if self.s_button["text"] == "RESUME":
self.s_button["text"] = "START"
self.p_button["text"] = "PAUSE"
self.ps.resume() #resume command for process
else:
str = 'test arg'
#queue = Queue()
self.p = multiprocessing.Process(None, test_function)
self.p.start()
self.ps = psutil.Process(self.p.pid)
self.s_button["state"] = 'disabled'
self.p_button["state"] = 'normal'
self.update_all()
self.after(500, self.check_proc) # Check to see if the process is done in 0.5 seconds
#p.join() #ending process
问题内容: 我正在尝试并行化脚本,但是由于未知的原因,内核只是冻结而没有引发任何错误。 最小的工作示例: 有趣的是,如果我在另一个文件中定义函数然后将其导入,则一切都可以正常工作。如何使它工作而无需另一个文件? 我使用spyder(anaconda),如果从Windows命令行运行代码,则结果相同。 问题答案: 发生这种情况是因为在子进程导入时,您没有保护代码的“过程”部分免于重新执行。 它们需要
TLDR:我有一个pyspark作业,当我在具有16个vcpus的ec2实例中运行它时,它会在10分钟内完成,但如果我使用具有超过20个vcpus的实例,它会冻结(它不会失败,只是永远不会完成)。我已经尝试了我能想到的一切,我只是不知道为什么会发生这种情况。 完整故事: 我有大约200个小型pyspark作业,出于成本和灵活性的考虑,我使用aws batch与spark dockers而不是EMR
我已经在处理中编写了一个算法来执行以下操作: 由于某种原因,这个算法会立即冻结。我在里面放了打印语句,显示它甚至在试图加载图像之前就冻结了。考虑到我已经编写了另一个非常相似的算法,并且执行起来没有并发症,这让我特别困惑。另一种算法读取图像,对指定大小的每块瓷砖的颜色取平均值,然后在用平均颜色取平均值的区域上打印矩形,有效地使图像像素化。两种算法都加载图像并检查其每个像素。这个算法的主要区别在于它没
我最近在我的项目中添加了一个很棒的UI库'antd'。https://ant.design/docs/react/introve
问题内容: 我有一个程序在其中加载文件,同时显示一个窗口以通知用户正在加载文件。我决定制作一个FileLoader类,它是一个实际上处理了文件加载的SwingWorker类,以及一个实现PropertyChangeListener的ProgressWindow,用于通知用户传递给它的SwingWorker的状态。 我的代码当前如下所示: 问题是,每当我调用loader.get()时,它都会冻结GU
问题内容: 我有一个JSON,我需要对其进行一些处理。它使用我需要以某种方式引用的切片,以便在函数末尾修改Room-struct。如何通过按引用类型同时使用此结构? http://play.golang.org/p/wRhd1sDqtb 问题答案: 您的逻辑中有两个不同的问题:第一个是切片本身的操作方式,第二个是实际的并发问题。 对于分片操作,仅按值传递分片作为参数将意味着您将无法以必须在增加分片