生成新进程时导入的模块变量会发生什么变化?
IE
with concurrent.futures.ProcessPoolExecutor(max_workers=settings.MAX_PROCESSES) as executor:
for stuff in executor.map(foo, paths):
哪里:
def foo(str):
x = someOtherModule.fooBar()
foobar访问someOtherModule开头声明的东西:
someOtherModule.py:
myHat='green'
def fooBar():
return myHat
具体来说,我有一个模块(称为Y),它在任何函数之外的顶部初始化了py4j网关.在模块X中,我一次加载多个文件,加载后对数据进行排序的函数使用Y中的函数,该函数又使用网关.
这个设计是pythonic吗?
在每个新进程生成后,我应该导入我的Y模块吗?或者有更好的方法吗?
解决方法:
在Linux上,fork将用于生成子进程,因此父进程的全局范围内的任何内容也将在子进程中可用,并具有写时复制语义.
在Windows上,您在父进程的__main__模块中的模块级别导入的任何内容都将在子进程中重新导入.
这意味着如果你有一个父模块(让我们称之为someModule),就像这样:
import someOtherModule
import concurrent.futures
def foo(str):
x = someOtherModule.fooBar()
if __name__ == "__main__":
with concurrent.futures.ProcessPoolExecutor(max_workers=settings.MAX_PROCESSES) as executor:
for stuff in executor.map(foo, paths):
# stuff
而someOtherModule看起来像这样:
myHat='green'
def fooBar():
return myHat
在此示例中,someModule是脚本的__main__模块.因此,在Linux上,你在子进程中获得的myHat实例将是someModule中的一个copy-on-write版本.在Windows上,每个子进程一加载就会重新导入someModule,这也会导致someOtherModule重新导入.
我不太了解py4j网关对象,以确定您是否确定这是否是您想要的行为.如果Gateway对象是pickleable,您可以显式地将它传递给每个子节点,但是您必须使用multiprocessing.Pool而不是concurrent.futures.ProcessPoolExecutor:
import someOtherModule
import multiprocessing
def foo(str):
x = someOtherModule.fooBar()
def init(hat):
someOtherModule.myHat = hat
if __name__ == "__main__":
hat = someOtherModule.myHat
pool = multiprocessing.Pool(settings.MAX_PROCESSES,
initializer=init, initargs=(hat,))
for stuff in pool.map(foo, paths):
# stuff
但是,您似乎并不需要为用例执行此操作.你很可能使用重新导入.