这是我的问题:使用Tkinter,我想点击一个按钮并启动一个python脚本。 这个python脚本现在是一个模块(我不知道它是否是最好的方法)导入到我的主脚本。 该脚本应该在后台运行。有一种方法可以退出它。我怎么称呼它? 我想把标志或东西传递给模块,但我不知道该怎么做。
现在,我这样调用我的代码:在gui.py中
import sniffer_wideband_v09
from Tkinter import *
root = Tk()
def handle_click():
global t
global stop_flag
stop_flag = 0
def callback():
sniffer_wideband_v09.main(sampling_rates, center_frequencies, gains, file_dir, files_names)
t = Thread(target=callback)
t.start()
root.mainloop()
我想在sniffer_wideband_v09.py中调用quitting()方法。或者将标志传递给我的模块以停止无限循环。 之后,我需要将所有这些绑定到Tkinter Buttons。
我对这个问题做了一些研究,发现:
Is there any way to kill a Thread in Python? 随着 How to run a function in the background of tkinter 和 How to run and stop an infinite loop in a python thread
第一个是有希望的,但我不完全理解它,我正在努力。
注意:我使用./gui.py直接从我的shell运行它,我在Ubuntu下,而不是windows。(我认为它可以改变一些处理多线程的方法)。
感谢阅读,任何提示或帮助将不胜感激。如果我在同一时间找到回复,我会发布我的代码。
编辑:提供有关在线程中启动的脚本的更多信息:(它是一个GNURadio脚本)
class foo():
def __init__(self):
self.parameters()
def methods():
self.dostuff()
def main(sampling_rates, center_frequencies, gains, file_dir, files_names):
tb = foo()
while True: #flag could be here to exit the infinite while.
tb.start()
tb.stop()
def quitting():
tb.stop()
## not mandatory piece of code from now on
if __name = "__main__":
main()
quitting()
答案 0 :(得分:3)
由于您的Tkinter gui应用程序与主要应用程序之间没有交互
你建议你从sniffer_wideband_09
模块调用的代码
使用多处理:
import sniffer_wideband_v09
import multiprocessing
from Tkinter import *
root = Tk()
def handle_click():
global t
t = multiprocessing.Process(target=sniffer_wideband_v09.main, args=(sampling_rates, center_frequencies, gains, file_dir, files_names))
t.start()
root.mainloop()
如果您想停止此过程,请拨打t.terminate()
。阅读有关多处理模块文档的更多信息。
答案 1 :(得分:1)
GUI工具包通常是事件驱动的。这意味着程序在循环处理事件(鼠标移动,点击,击键,计时器等)中运行。
通常有三种方法可以在事件驱动的程序中运行长时间运行的计算;
第一种解决方案相对简单。你设置了一个计时器。该计时器将在用完后生成一个事件或调用回调函数(取决于工具包)。您在回调中做了一些工作,保存计算状态,可能更新进度指示器,重新启动计时器并退出回调。这与GUI完美融合,但需要对代码进行结构化,以便将工作分成小块。如果回调时间过长,则事件处理将受到影响,GUI将无法响应。回调应该不会超过例如在10到100毫秒之间。这种方法无法利用现代CPU中普遍存在的多核。
第二种解决方案是开始一个单独的过程,正如mguijarr所证明的那样。在CPython上,这是一个非常好的解决方案,因为你根本不会影响GUI,你仍然可以使用各种方法(信号,套接字,共享内存,消息队列)与外部程序通信。这将利用多个核心。使用multiprocessing.Pool
,您甚至可以在所有可用核心上分配工作。
另一方面,在这种情况下,线程不是CPython中的最佳解决方案。全局解释器锁(“GIL”)限制CPython解释器,以便一次只有一个线程可以执行Python字节码。这最初是为了简化内存管理。因此,即使您使用单独的线程进行计算,您仍然可以使处理器时间的GUI处于饥饿状态并使其无响应。并且您必须使用锁保护多个线程使用的数据。使用大多数GUI工具包,只有一个线程可以调用工具包函数。所以你不能,例如从第二个帖子更新进度指示器。
答案 2 :(得分:0)
我花了几个小时尝试使用线程来解决你自己的启发问题,并且几个没有响应的UI后来最终得到了这个:TkInter不是线程安全的,来自 tkinter tkMessageBox not working in thread