【问题标题】:Python Multithreading - not running simultaneouslyPython多线程 - 不同时运行
【发布时间】:2018-12-12 07:20:18
【问题描述】:

我正在尝试学习 python。但是我的线程有问题。首先我在“Proces”类中失败了,因为我把循环放在了错误的地方,我的程序更新从另一个类返回。

但现在我认为一切都是正确的,但它仍然不起作用。 我需要一个 GUI,我希望能够通过文本条目编写我的条件,并且我需要另一个类“Proces”来做一些事情,不断地或在指定的时间间隔检查互联网的状态等等。 .

问题是我的 tkinter GUI 在按下某些东西后冻结了

这是我的 GUI.py 文件:

import tkinter as tk
from Proces import Proces


root = tk.Tk()
frame = tk.Frame(root)
frame.pack()
button = tk.Button(frame, text="QUIT", fg="red",command=quit).pack(side=tk.LEFT)

pr = Proces()
print("\nGUI: proces init...")
pr.start()
print("\nGUI: Start ended")

root.mainloop()

这是 Proces.py 文件:

import time, threading


class Proces(threading.Thread):
    def loop(self):
        while True:
            time.sleep(2)
            print("\nProces: looping")

    def __init__(self):
        threading.Thread.__init__(self)
        print("\nProces: Starting proces")
        time.sleep(2)

    def run(self):
        self.deamon = True
        print("\nProces: Starting loop")
        self.loop()

*这是输出:*

Proces: Starting proces
GUI: proces init...
Proces: Starting loop
GUI: Start ended
Proces: looping
Proces: looping
Proces: looping
Proces: looping

*但是tkinter的GUI没有反应。*

我应该如何做这样的任务? 感谢您的帮助、建议和回答

【问题讨论】:

  • 你的Proces.__init__为什么要睡2秒?这个睡眠是在主线程上,所以停止渲染 GUI 直到它结束?
  • Proces 类中有错字,应该是self.daemon = True,而不是self.deamon = True
  • @JamesKent 睡眠只是因为我还在学习,只是为了测试延迟线程
  • @j_4321 我没有注意到守护进程拼写错误。但我想知道为什么另一个线程没有以第一个线程结束。谢谢

标签: python multithreading tkinter


【解决方案1】:

我认为您在启动线程等方面没有问题。但是,您应该能够控制您的线程,这意味着您的线程应该根据某些条件返回。看来您有一个退出按钮。我假设您想通过单击按钮来完成该过程。 为此,当您单击按钮时,您的主线程应该将一个变量传递给 Process 以打破您的 while 循环,这基本上是您的线程。 这是您可以处理的代码。

import tkinter as tk
import time
import threading


class MainWindow:
    def __init__(self, master):

    self.master = master
    self.quit_button = tk.Button(self.master, text="QUIT", command=lambda:self.quit(), width=20)
    self.quit_button.pack(side=tk.LEFT)
    self.process = None
    print("\nGUI: process init...")
    self.start_task()


    def quit(self):
      self.process.stop_process = True
      print("\nGUI: Start ended")

    def start_task(self):
      self.process = Process()
      self.process.start()


class Process(threading.Thread):
    def loop(self):
        while True:
            if not self.stop_process:
                time.sleep(2)
                print("\nProcess: looping")
            else:
                print("\nProcess: looping ended")
                return

    def __init__(self):
        threading.Thread.__init__(self)
        self.stop_process = False
        print("\nProcess: Starting proces")
        time.sleep(2)

    def run(self):
        self.deamon = True
        print("\nProcess: Starting loop")
        self.loop()


if __name__ == '__main__':
    root = tk.Tk()
    app = MainWindow(master=root)
    root.mainloop()

所以你启动你的 tkinter,这是你的主线程。然后在你的主线程中启动另一个类,它继承了线程。所以你有两个单独的线程在工作。当您单击“退出”按钮时,您传递变量stop_process,它会中断循环并返回,这意味着结束您的线程。您的主线程仍然可以运行您的 tkinter 窗口。

希望对你有帮助

【讨论】:

  • 您的代码有效,是的,它有帮助。但我不明白为什么 GUI 窗口在单击后会在我的程序中冻结。 在代码中,我故意删除了退出功能,因此没有太多需要关注的代码。但它所做的只是 "print("klik")"
  • 我的意思是点击不在框架中的按钮
  • @Tomas 您好,如果您删除退出按钮,您的第二个线程将无限运行,除非您以其他方式返回“进程”。我写的程序不应该冻结。例如,您可以在窗口中添加一个文本小部件。程序将运行线程,同时您可以与主窗口进行交互,例如在文本字段中输入。因为,你的主窗口和你的进程在不同的线程中运行。