我正在尝试在C类的构造函数中导入mymodule.py
,以便在使用多处理方法将f
方法调用为新过程时,C类的每个新实例使用其自己的mymodule。模块。
请查看以下代码:
mymodule.py
import random
n = random.randint(0, 1000)
mp_test.py
import time
import multiprocessing as mp
import imp
class C(object):
def __init__(self, c='*'):
self.mm=imp.load_module('mm', *imp.find_module('mymodule'))
self.c = c
def f(self):
print self.c, id(self.mm), id(self.mm.n), self.mm.n
def main():
p = []
for _ in range(2):
p.append(mp.Process(target=C().f))
p[-1].start()
time.sleep(1)
print ''
p0 = mp.Process(target=C(c='>').f)
p1 = mp.Process(target=C(c='>').f)
p0.start()
p1.start()
if __name__ == '__main__':
main()
执行mp_test.py
后,标准输出为:
funk@linux:~/mp_test# python mp_test.py
* 140679674677800 94828316092856 40
* 140679674677800 94828316835224 486
> 140679674677800 94828317211688 763
> 140679674677800 94828317211688 763
如预期的那样,以下代码创建了mymodule
的不同实例,因此生成了两个不同的随机数:
p = []
for _ in range(2):
p.append(mp.Process(target=C().f))
p[-1].start()
* 140679674677800 94828316092856 40
* 140679674677800 94828316835224 486
按以下方式调用start()
方法时,mymodule
不会被导入两次,因此随机数是相同的...
p0 = mp.Process(target=C(c='>').f)
p1 = mp.Process(target=C(c='>').f)
p0.start()
p1.start()
> 140679674677800 94828317211688 763
> 140679674677800 94828317211688 763
请提出您的想法...!
修改
zwer的suggestion解决了该问题:
代码更正
# ERROR self.mm=imp.load_module('mm', *imp.find_module('mymodule'))
self.mm=imp.load_module('mm_' + str(uuid.uuid4()), *imp.find_module('mymodule'))
更新结果
funk@linux:~/mp_test# python -O mp_test.py
* 139813126327944 94540189500648 396
* 139813126447184 94540189500504 491
> 139813126447296 94540189500432 847
> 139813126447240 94540189500384 389
请注意,代表id(self.mm)
的最新结果的第一列始终是不同的!
答案 0 :(得分:1)
您的问题没有与多处理程序直接关联,因此,在尝试将f()
方法作为单独的进程运行之前,请在同一进程中进行模块加载。这会导致模块缓存,因此下次您尝试导入它时,Python会为您提供一个缓存的实例,在该实例中不会再执行随机部分。
在第一种情况和第二种情况下获得不同结果的原因是,在创建C
实例后,您立即产生了一个进程(因此派生/拆分了上下文),而您并没有为此付出很多第二种方法,首先实例化C
实例,然后启动新流程-例如如果您要这样做:
p0 = mp.Process(target=C(c='>').f)
p0.start()
p1 = mp.Process(target=C(c='>').f)
p1.start()
您也会得到预期的结果。
也就是说,如果要在同一过程中多次加载同一模块,同时又要避免缓存,则在加载时必须给它起一个不同的名称,例如:
class C(object):
load_counter = 0
def __init__(self, c='*'):
self.mm=imp.load_module('mm' + str(C.load_counter), *imp.find_module('mymodule'))
C.load_counter += 1
self.c = c
或者在生成的进程中加载模块(在其上的之后调用start()
)。如果您在保留缓存的模块时只想获得不同的结果(即无需重新评估),则将模块逻辑放入函数中,然后执行该函数。
答案 1 :(得分:0)
例如,我相信您在Unix系统(例如Linux)上,用于创建子进程的默认策略是forking。
子进程继承其父级的执行状态和内存状态,包括导入的Python模块。您说第二次未导入mymodule
时,您是正确的。
您实际上想使用以下函数将代码包装在mymodule
中:
import random
def get_random():
return random.randint(0, 1000)
,然后从您的mp_test.C.f()
方法调用它:
def f(self):
print self.c, id(self.mm), id(self.mm.get_random()), self.mm.get_random()