2013-11-26 110 views
1

我正在研究需要在后台执行大量计算的GUI,然后在计算完成时更新GUI。多处理模块似乎是一个很好的解决方案,因为我可以使用* apply_async *方法来指定目标和回调函数。回调函数用于更新GUI的结果。不过,当我尝试将多处理与动态加载的模块结合使用时,我遇到了困难,如下面的代码所示。错误消息是ImportError:没有名为calc的模块。将动态加载的函数用作多处理目标。池

错误是由于多处理对动态加载模块不起作用的事实吗?如果不是,有没有更好的方法的想法?

from PySide.QtCore import * 
from PySide.QtGui import * 
import multiprocessing 
import time 
import sys 
import os 
import logging 
import imp 

PluginFolder = "plugins" 
plugins = {} 

def f(x): 
    y = x*x 
    time.sleep(2) #Simulate processing time. 
    return y 


def load_plugin(name): 
    '''Load the python module 'name' 
    ''' 
    location = os.path.join('.', PluginFolder) 
    info = imp.find_module(name, [location]) 
    plugin = {"name": name, "info": info} 
    plugins[name] = imp.load_module(name, *plugin["info"]) 


class MainWindow(QMainWindow): 

    def __init__(self): 
     super(MainWindow, self).__init__() 
     self.pool = multiprocessing.Pool() 
     load_plugin('calc') #load ./plugins/calc.py 

     button1 = QPushButton('Calculate', self) 
     button1.clicked.connect(self.calculate) 
     button2 = QPushButton('Test', self) 
     button2.clicked.connect(self.run_test) 
     self.text = QTextEdit() 

     vbox1 = QVBoxLayout() 
     vbox1.addWidget(button1) 
     vbox1.addWidget(button2) 
     vbox1.addWidget(self.text) 
     myframe = QFrame() 
     myframe.setLayout(vbox1) 

     self.setCentralWidget(myframe) 
     self.show() 
     self.raise_() 



    def calculate(self): 
     #self.pool.apply_async(f, [10], callback=self.update_gui) #This works 

     #result = plugins['calc'].f(10) #this works 
     #self.update_gui(result) 

     self.pool.apply_async(plugins['calc'].f, [10], callback=self.update_gui) #This doesn't 


    def update_gui(self, result): 
     self.text.append('Calculation complete. Result = %d\n' % result) 


    def run_test(self): 
     self.text.append('Testing\n') 


if __name__ == '__main__': 
    app = QApplication(sys.argv) 
    gui = MainWindow() 
    app.exec_() 

在./plugins/calc.py中,函数f的定义与上面的代码一样。

回答

1

这不起作用,因为您正在将calc模块加载为顶级模块。由于sys.path或当前目录中没有模块calc,因此无法通过导入语句找到它。更换import语句与下面将这样的伎俩:

plugins[name] = imp.load_module('{}.{}'.format(PluginFolder, name), 
        *plugin["info"]) 

对于plugin.calc被导入的,plugins必须是一个Python模块,即包含一个__init__.py文件。

任何import <module>声明你的插件文件,如在plugins/calc.py,将导致一个警告,

RuntimeWarning: Parent module 'plugins' not found while handling absolute import import <module> 

的原因是导入过程看起来如果父模块包含<module>,虽然里面calc.py,可以” t找到父母plugins模块。您可以用主代码中的import plugins语句排除指定plugins模块位置的爆炸性错误。

+0

这似乎并不奏效。有一个警告:_。\ plugins \ calc.py:6:RuntimeWarning:在处理绝对导入时找不到父模块'plugins',出现错误:_PicklingError:无法pickle :attribute lookup __builtin__ .function failed_ –

+0

@mr_js请澄清你的代码结构,你有'__init __。py'在'plugins'文件夹中;你的主代码在哪里? – alko

+0

谢谢。解决方案是将'__init __。py'添加到插件文件夹中,现在将您的名称更改为'plugins.calc'的工作方式。但是,警告仍然存在:_。\ plugins \ calc.py:6:RuntimeWarning:处理绝对导入时找不到父模块'plugins' import time_ –