【问题标题】:Threading and Queuing with Functions使用函数进行线程化和排队
【发布时间】:2013-07-24 04:30:17
【问题描述】:

我一直在多线程和 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 和不同的函数(我有一个稍后在程序中相同的使用它只是具有不同的功能)我不喜欢ThreadedClient1ThreadedClient2,唯一的区别是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)

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

我做错了什么?

编辑: 问题解决了。然而,另一个出现了。我想将spawnthreadperiodiccallThreadedClient 转移到我拥有的小部件模板模块中并对其进行概括,以便我可以轻松使用它们。我这样做了:

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,我希望它通过在after 语句中调用self.periodiccall 来实现。至少,这就是我认为正在发生的事情。如何删除此错误并使小部件成为此递归函数中的变量?

【问题讨论】:

    标签: python multithreading lambda tkinter queue


    【解决方案1】:

    问题是当您将其用作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())
    

    【讨论】:

    • 完美。这正是我所需要的。我使用 lambdas 是因为我希望能够将 spawnthread、periodall 和 threadedclient 转储到我的小部件模板模块中以保持代码的整洁。
    • 我确实有一个后续问题;我将其添加到原始问题中。
    猜你喜欢
    • 2018-12-09
    • 1970-01-01
    • 2010-12-09
    • 1970-01-01
    • 1970-01-01
    • 2021-03-05
    • 2013-06-16
    • 2012-09-26
    相关资源
    最近更新 更多