【问题标题】:Tkinter and multiprocessingTkinter 和多处理
【发布时间】:2019-09-19 15:16:49
【问题描述】:

我有一个模块调用另一个模块,我用 tkinter 和一个按钮初始化一个画布。当用户单击按钮时,它会从第一个模块启动一个功能。但是这个函数很长,我不想让 tkinter 冻结,直到函数完全执行。似乎多处理将是解决方案,但我在实施它时遇到了一些困难。

在第一个模块中:

tkinterModule.initialize(functionFromMainModule)

在第二个模块中:

...
button = Button(master, 
                 text="Launch Function", 
                 command=partial(play, callback))

def play(callback=None):
     if callback is not None:
         callback()

然后在第一个模块中:

def functionFromMainModule():
    ....
    if __name__ == '__main__':
        p = multiprocessing.Process(target=longFunction)
        p.start()

def longFunction():
    ...

但不是启动 longFunction 它只是重新初始化一个新的 tkinter 画布并且不启动该函数。如果我只是调用该函数而不使用多处理,则该函数将正常调用(但 tkinter 被冻结直到执行结束)。

【问题讨论】:

  • 所有 GUI 都应该在一个线程中。其他线程或进程只应进行计算并将结果或信息发送到将更改 GUI 的主线程。
  • 也许可以为您的问题创建最小的工作示例,以便我们运行它。
  • 也许你应该运行if __name__ == '__main__':中的所有代码,而不仅仅是多进程。
  • 你在windows上吗?如果是,您应该使用if __name__ == '__main__' 声明

标签: python tkinter python-multiprocessing


【解决方案1】:

嗯 我想,你在 Windows 上,所以你的问题是当一个新进程启动时,Python 是 pickle-ing 你的模块(或包)中的所有代码(这是因为 windows restrictions)

因此,当您使用多处理模块时,您应该使用if __name__ == '__main__': 语句。原因如下:

当您的代码经过腌制后,它将在另一个进程中运行,并且与主进程相同,但__name__ 变量除外。这个变量可以保存代码作为主程序运行。由于这个错误,您的程序会清除画布,然后从头开始工作。

【讨论】:

  • 行得通!当您在进程中实际指定一个函数时,我很惊讶模块中的整个代码会重新运行:p = multiprocessing.Process(target=longFunction)
【解决方案2】:

解决此问题的一个可能方法是使用线程。 Python 有一个名为 threading 的模块。您可以使用此模块创建线程,以便您的 tkinter 应用程序不会冻结。这是它的样子。

import threading

def Function(Data):
   print(Data)

thread = threading.Thread(target=Function, args=["Hi"], daemon=True).start()

# daemon simply means that the thread will die once done executing.

我们创建一个线程,称为线程。线程将执行该函数。线程将程序划分为同时运行的任务。换句话说,这意味着可以同时运行两个或多个任务。同一进程中的线程使用相同的内存和资源,而进程则不使用。您还可以使用 threading 模块在类中创建线程。只需导入线程模块并在一个类中继承它。例如,

import threading

class Animal(threading.Thread):
    def __init__(self, v):

        threading.Thread.__init__(self, Variable):  # init for threaded classes
        self.Variable = Variable
        self.Run()
    def Run(self):
        print("I am an animal")


A = Animal("Snake")

A.start()

如果您希望一个对象在不减慢您的应用程序并使其崩溃和冻结的情况下运行,这是一件很棒的事情。

【讨论】:

  • 这不是它的做法。不应该做的一件事就是像您一样呼叫目标。相反,只允许将可调用和附加参数作为 args 参数或通过 functools.partial 传递。
  • 我也很遗憾地说,但您的基于类的示例也不起作用。案件很重要。您需要改为调用 Run ˋrunˋ,但更重要的是 START 线程。并调用ˋThread.__init__ˋ.
  • 感谢您纠正我所说的。我写错了。
  • 为什么叫它运行
  • Deets。如果我们不能调用目标那么我们如何执行线程?
猜你喜欢
  • 2022-01-05
  • 2020-09-28
  • 1970-01-01
  • 1970-01-01
  • 2015-11-07
  • 1970-01-01
  • 1970-01-01
  • 2020-10-05
  • 1970-01-01
相关资源
最近更新 更多