通过文件路径导入模块时使用 Python 多处理
Posted
技术标签:
【中文标题】通过文件路径导入模块时使用 Python 多处理【英文标题】:Using Python multiprocessing while importing a module via file path 【发布时间】:2010-10-24 04:02:15 【问题描述】:我正在编写一个程序,它使用文件路径导入模块,函数imp.load_source(module_name,module_path)
。当我尝试将此模块中的对象传递到Process
时,这似乎会导致问题。
一个例子:
import multiprocessing
import imp
class MyProcess(multiprocessing.Process):
def __init__(self,thing):
multiprocessing.Process.__init__(self)
self.thing=thing
def run(self):
x=self.thing
if __name__=="__main__":
module=imp.load_source('life', 'C:\\Documents and Settings\\User\\workspace\\GarlicSim\\src\\simulations\\life\\life.py')
thing=module.step
print(thing)
p=MyProcess(thing)
p.start()
注意:要“工作”此代码,您必须将我提供给 imp.load_source
的参数替换为其他内容:它必须是您计算机上的某个 Python 文件,最好不在同一个文件夹中。然后,在 thing=module.step
中,而不是 step 放入该 .py
文件中定义的一些随机函数或类。
我得到以下回溯:
<function step at 0x00D5B030>
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "C:\Python26\lib\multiprocessing\forking.py", line 342, in main
self = load(from_parent)
File "C:\Python26\lib\pickle.py", line 1370, in load
return Unpickler(file).load()
File "C:\Python26\lib\pickle.py", line 858, in load
dispatch[key](self)
File "C:\Python26\lib\pickle.py", line 1090, in load_global
klass = self.find_class(module, name)
File "C:\Python26\lib\pickle.py", line 1124, in find_class
__import__(module)
ImportError: No module named life
那我该怎么办?
编辑:
我在 Win XP 上使用 Python 2.6.2c1。
【问题讨论】:
【参考方案1】:test.py
在任何文件夹上:
import multiprocessing
import imp
class MyProcess(multiprocessing.Process):
def __init__(self,thing):
multiprocessing.Process.__init__(self)
self.thing=thing
def run(self):
print 'running...', self.thing()
if __name__=="__main__":
module=imp.load_source('life', '/tmp/life.py')
thing=module.step
print(thing)
p=MyProcess(thing)
p.start()
life.py
/tmp
:
def step():
return 'It works!'
运行test.py
:
$ python test.py
<function step at 0xb7dc4d4c>
running... It works!
我刚刚测试并且它有效,所以你一定做错了什么。请编辑您的问题并粘贴不起作用的真实代码。
我正在使用带有默认 python 的 ubuntu Jaunty 9.04(Python 2.6.2 release26-maint,2009 年 4 月 19 日,01:56:41)。不知道您的问题是否仅限于 Windows,因为我没有可用于测试的 Windows。
这就是修改导入路径是一个坏主意的原因。您永远无法在所有平台/环境中正确使用它,您的用户可能会生气。最好只使用 python 查找模块的方式,即将模块放在 python 模块搜索路径上。这将在任何地方始终如一地工作。
【讨论】:
我复制了您的代码,只是将'/tmp/life.py'
更改为 'tmp\\life.py'
,(我在 Windows XP 上。)我得到了一个回溯,我认为它与我的问题中的相同,与最后是pickle
模块。也许它只发生在 Windows 上? (注:我使用的是 Python 2.6.2c1)
使用带有默认 python 的 ubuntu Jaunty 9.04(Python 2.6.2 release26-maint,2009 年 4 月 19 日,01:56:41)。不知道是不是只有windows,我没有windows可供测试。请注意,您也可以在 Windows 上使用正斜杠 /tmp/life.py,无需将其更改为反斜杠。【参考方案2】:
我刚刚完成了以下操作,在带有 Python 2.5 的 XP 上运行...
D:\Experiments\ModuleLoading\test.py
import imp
if __name__=="__main__":
module=imp.load_source('life', r'D:\Experiments\ModuleLoading\somefolder\life.py')
thing=module.step
print(thing)
D:\Experiments\ModuleLoading\somefolder\step.py
def step():
return 'It works!'
...运行脚本给出:
D:\jcage\Projects\Experiments\ModuleLoading>test.py
<function step at 0x00A0B470>
...所以先试试看,确保模块可以在没有多处理的情况下加载?
[编辑] 好的,所以导入分叉进程肯定是个问题。有some bits and pieces in the documentation which are specific to windows:
更易腌制
确保 Process.__init__() 的所有参数都是可提取的。这尤其意味着,绑定或未绑定的方法不能直接用作 Windows 上的目标参数——只需定义一个函数并使用它来代替。 此外,如果您将 Process 子类化,请确保在调用 Process.start() 方法时实例是可挑选的。
全局变量
请记住,如果在子进程中运行的代码尝试访问全局变量,那么它看到的值(如果有)可能与 Process.start( ) 被称为。 但是,只是模块级常量的全局变量不会造成任何问题。
安全导入主模块
确保新的 Python 解释器可以安全地导入主模块,而不会导致意外的副作用(例如启动新进程)。
[Edit2] 有什么原因导致你不能在这个过程中进行导入吗?我认为问题在于,当您启动新进程时,它并未在同一地址空间中运行,因此尝试访问原始线程中的函数将无法正常工作。
您可以改为为 D:\Experiments\ModuleLoading\test.py
执行此操作:
from multiprocessing import Process
import imp
class MyProcess(Process):
def __init__(self):
Process.__init__(self)
def run(self):
print 'run called...'
module=imp.load_source('life', r'D:\Experiments\ModuleLoading\somefolder\life.py')
print 'running...', module.step()
if __name__=="__main__":
p=MyProcess()
p.start()
【讨论】:
需要反斜杠,但在您的情况下,您不会碰巧有任何转义。 'D:\foo\bar\quux\life.py' 变为 D:ooar\quux\life.py。而是使用 r'D:\foo\bar\quux\life.py',它正确地变为 D:\foo\bar\quux\life.py 无论我使用 \ 或 / 还是 \\,我都会遇到相同的错误。显然模块正在主进程中加载:否则print(thing)
将失败。【参考方案3】:
可能由于将导入代码放置在主块中而无法正常工作。 下面的代码适用于 Windows XP、Python 2.6。然后生命模块也将在新进程中导入。
import multiprocessing
import imp
class MyProcess(multiprocessing.Process):
def __init__(self,thing):
multiprocessing.Process.__init__(self)
self.thing=thing
def run(self):
print("Exiting self.thing")
self.thing()
print("Finished")
life=imp.load_source('life', r'd:\temp5\life.py')
if __name__=="__main__":
p=MyProcess(life.step)
p.start()
【讨论】:
以上是关于通过文件路径导入模块时使用 Python 多处理的主要内容,如果未能解决你的问题,请参考以下文章