Python 为什么从工作线程更新tkinter小部件似乎有效?

Python 为什么从工作线程更新tkinter小部件似乎有效?,python,multithreading,tkinter,Python,Multithreading,Tkinter,在研究tkinter多线程时,我发现tkinter必须在主线程上运行(就像许多GUI框架一样),当一个单独的线程需要与GUI通信时,必须使用队列,而不是直接从工作线程访问小部件 我试图学习使用queue方法,但当然,一开始我想看看如果我做错了会发生什么,所以我写了这段代码,它在几秒钟内近似于Pi(π): import tkinter as tk from tkinter import ttk from threading import Thread import math window = t

在研究tkinter多线程时,我发现tkinter必须在主线程上运行(就像许多GUI框架一样),当一个单独的线程需要与GUI通信时,必须使用队列,而不是直接从工作线程访问小部件

我试图学习使用queue方法,但当然,一开始我想看看如果我做错了会发生什么,所以我写了这段代码,它在几秒钟内近似于Pi(π):

import tkinter as tk
from tkinter import ttk
from threading import Thread
import math

window = tk.Tk()
window.geometry("300x150")

lbl = tk.Label(window, text="Press Start")
lbl.place(width=280, height=60, x=10, y=10)

pb = ttk.Progressbar(window)
pb.place(width=280, height=25, x=10, y=80)

def calculate():
    """ 1 / i^2 =  PI^2 / 6 """
    s = 0.0
    for i in range(1, 10000001):
        s += (1 / i**2)
        if i % 1000000 == 0:            
            value = math.sqrt(s * 6)
            lbl.config(text=value) #???
            pb.step(10) #???

def start():
    lbl.config(text="Press Start")
    #calculate() #irresponsive GUI this way, obviously
    t = Thread(target=calculate)
    t.start()

btn = tk.Button(window, text="Start", command=start)
btn.place(width=280, height=25, x=10, y=115)

window.mainloop()
据我所知,问题出在标有
注释的行上。但是这段代码运行得很好。保持响应,标签和进度条都会更新


就有时发生/有时不发生而言,这个跨线程错误是不确定的吗?这段代码最终会被破解吗?还是我天真地认为唯一好的解决办法就是排队?我相信C#会产生一个无效的
跨线程操作
,但python似乎没有问题

在常规的消费者应用程序中,有一件事是不可接受的:当你点击“开始”按钮,然后在进度条结束前关闭窗口时会发生什么?在具有相互依赖部分的大型应用程序中,销毁另一个线程中使用的gui元素可能会产生不愉快的后果。我发现,当在终端中运行时,这个程序有时会在意外的出口处挂起,以至于ctrl-c无效

顺便说一句

s += (1 / i ** 2)

行正在进行整数除法,因此
s
的值只更改一次

在这段代码中,它太简单了,没有问题。当您有许多线程试图同时更新同一个小部件时,就会出现问题。@dilbert我理解,谢谢。可能是我编写的类似代码的重复,该代码在Mac(python 3.6)上运行良好,但在Linux(python 3.5)上崩溃。错误是“堆栈空间不足(无限循环?)”谢谢。是的,它真的应该是
/
。我明白你关窗的意思,但排队也不能解决这个问题,不是吗?所以这是另一个问题。