Skip to main content
 首页 » 编程设计

python之函数的线程和队列

2025年05月04日12bhlsheji

我一直在使用多线程和 tkinter 时遇到困难。 slxl 是我使用的一个模块,它的功能不返回值(只是为了确保没有混淆。)

这是过去有效的代码:

    #relevant tkinter code 
    def create_widgets(): 
 
        self.updatebttn = Button(self, text='Auto Update', command=self.spawnthread) 
        self.updatebttn.grid(row=1, column=0, sticky=N) 
 
        self.progressbar = Progressbar(self, orient='horizontal', 
                                       length=300, mode='determinate') 
        self.progressbar.grid(row=1, column=1, sticky=W) 
        self.progressbar["maximum"] = (slxl.sizeFinder()) * 1.1 
 
 
    def spawnthread(self): 
        self.updatebttn.config(state="disabled") 
        self.thread = ThreadedClient1(self.queue) 
        self.thread.start() 
        self.periodiccall() 
 
    def periodiccall(self): 
        if self.thread.is_alive(): 
            self.after(100, self.periodiccall) 
            self.progressbar.step(500) 
        else: 
            self.updatebttn.config(state="active") 
            self.progressbar.stop() 
 
class ThreadedClient1(threading.Thread): 
    def __init__(self, queue): 
        threading.Thread.__init__(self) 
        self.queue = queue 
    def run(self): 
        time.sleep(1) 
        importer = slxl.runImportAndCoordAdder() 
        self.queue.put(importer) 

问题是,我希望 ThreadedClient1 能够获取它放入队列的函数,在本例中 slxl.runImportAndCoordAdder() 作为参数,因为我使用 ThreadedClient 不止一次使用不同的函数(稍后我在程序中使用了相同的函数,只是使用了不同的函数)而且我不喜欢 ThreadedClient1 和 ThreadedClient2,唯一的区别是 importer = 不同的功能。

我确实尝试过这样的 lambda 解决方案:

def spawnthread(self): 
    self.updatebttn.config(state="disabled") 
    self.thread = ThreadedClient1(self.queue, lambda: slxl.runImportAndCoordAdder()) 
    self.thread.start() 
    self.periodiccall() 
 
#periodic call is the same 
 
class ThreadedClient1(threading.Thread): 
    def __init__(self, queue, fcn): 
        threading.Thread.__init__(self) 
        self.queue = queue 
        self.fcn = fcn 
    def run(self): 
        time.sleep(1) 
        self.queue.put(lambda: self.fcn) 

这没有用,因为它忽略了我感兴趣的功能,稍微调整了进度条/禁用并启用了按钮,然后结束。

我做错了什么?

编辑: 问题解决了。不过,另一个出现了。我想将 spawnthread、periodiccall 和 ThreadedClient 转移到我拥有的小部件模板模块中,并将它们概括化,以便我可以轻松地使用它们。我这样做了:

def spawnthread(self, widget): 
    widget.config(state="disabled") 
    self.thread = ThreadedClient1(self.queue) 
    self.thread.start() 
    self.periodiccall() 

这很有效,直到我也尝试概括 periodiccall。

    #... 
        self.periodiccall(widget=widget) 
 
    def periodiccall(self, widget=None): 
        if self.thread.is_alive(): 
            self.after(100, self.periodiccall) 
            self.progressbar.step(500) 
            #print widget 
        else: 
            widget.config(state="active") 
            self.progressbar.stop() 

我在 print widget 中弹出以查看发生了什么,因为我不断收到属性错误。似乎正在发生的事情是,它第一次通过函数运行时它知道“小部件”是什么,然后它变成了 None 我希望通过调用 self.periodiccall 在 after 语句中。至少,这就是我认为正在发生的事情。如何消除此错误并使小部件成为此递归函数中的变量?

请您参考如下方法:

问题是当您将函数用作 ThreadedClient1 的参数时,您没有调用该函数:

class ThreadedClient1(threading.Thread): 
    # ... 
    def run(self): 
        time.sleep(1) 
        self.queue.put(lambda: self.fcn) 

它只是一个返回对作为参数传递的 lambda 的引用的函数,而不是调用 slxl.runImportAndCoordAdder() 的结果。应该是:

class ThreadedClient1(threading.Thread): 
    # ... 
    def run(self): 
        time.sleep(1) 
        self.queue.put(self.fcn()) 

或者直接使用引用的另一种解决方案(没有 lambda):

def spawnthread(self): 
    self.updatebttn.config(state="disabled") 
    self.thread = ThreadedClient1(self.queue, slxl.runImportAndCoordAdder) 
    self.thread.start() 
    self.periodiccall() 
 
class ThreadedClient1(threading.Thread): 
    # ... 
    def run(self): 
        time.sleep(1) 
        self.queue.put(self.fcn())