我正在开发一个内部应用程序,用于使用Tkinter进行图像处理/计算机视觉。我过去常常通过一些代码来破解和快速运行,并且用户友好不在我的经验范围内。在启动程序的耗时部分之前,最终用户需要手动设置一些值。
我遇到的问题是:由于正在处理的图像数量,程序需要很长时间(约1小时)。当我将处理分为4个核心时,我看到了显着的加速(大约三分之一的时间)(仅供参考 - 流程之间不需要通信);但是,当我尝试从Tkinter类启动一个新进程时,我收到了错误。
彻底地在我的头上,我已经长期屈服于复制粘贴succubi诱人的诱惑,现在几乎不理解我正在尝试的任何东西。我发现类似的问题here和here,并且实施其中建议的更改会将我的错误换成新的错误。请参阅以下所有错误。
初步尝试:
import Tkinter
from multiprocessing import Manager, Pool
class userApp(Tkinter.Frame):
def multi_proc(self):
arg_gen = ((n) for n in self.values)
manager = Manager()
self.ret = manager.dict()
pool = Pool(4)
jobs = pool.map_async(self.func2, arg_gen)
self.ret = jobs.get()
def func1(self):
self.values = range(15)
def func2(self,args):
return("I'm #%d"%(args[0]))
def _quit(self):
self.quit()
def createWidgets(self):
self.button1 = Tkinter.Button(root,text="Set some values",command=self.func1)
self.button2 = Tkinter.Button(root,text="Start processes",command=self.multi_proc)
self.button3 = Tkinter.Button(root,text="Quit",command=self._quit)
self.button1.pack()
self.button2.pack()
self.button3.pack()
def __init__(self, master=None):
Tkinter.Frame.__init__(self, master)
self.pack()
self.createWidgets()
root = Tkinter.Tk()
root.title("Select an option")
if __name__ == '__main__':
app = userApp(master=root)
app.mainloop()
root.destroy()
这会返回以下错误:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Anaconda\lib\lib-tk\Tkinter.py", line 1486, in __call__
return self.func(*args)
File "C:\...\TestScript.py", line 13, in multi_proc
self.ret = jobs.get()
File "C:\Anaconda\lib\multiprocessing\pool.py", line 558, in get
raise self._value
PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed
将func2()
包装在Tk应用之外并将参数发送到包装器会导致不同的pickling
错误:
class userApp(Tkinter.Frame):
...
def multi_proc(self):
arg_gen = ((n) for n in self.values)
manager = Manager()
self.ret = manager.dict()
pool = Pool(4)
jobs = pool.map_async(unwrap_self_f, zip([self]*len(self.values), arg_gen))
self.ret = jobs.get()
...
def unwrap_self_f(arg, **kwarg):
return userApp.func2(*arg, **kwarg)
抛出:
... same as before ...
UnpickleableError: Cannot pickle <type 'tkapp'> objects
最后(抱歉这篇长篇文章),将其添加到课程中:
def __getstate__(self):
state = self.__dict__.copy()
del state['view']
return state
抛出这个:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Anaconda\lib\lib-tk\Tkinter.py", line 1486, in __call__
return self.func(*args)
File "C:\...\TestScript.py", line 13, in multi_proc
self.ret = jobs.get()
File "C:\Anaconda\lib\multiprocessing\pool.py", line 558, in get
raise self._value
KeyError: 'view'
我知道未来的自我会回顾现在的自我并告诉我,我是一个白痴,但在此期间,任何帮助或方向都会受到赞赏。