2013-11-26 79 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_ –