如何在后台运行无限循环并停止它?

时间:2014-07-29 08:05:58

标签: python multithreading python-2.7 tkinter

这是我的问题:使用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 tkinterHow 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()

3 个答案:

答案 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