python – 生成新进程时导入会发生什么?

生成新进程时导入的模块变量会发生什么变化?

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()

foob​​ar访问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

但是,您似乎并不需要为用例执行此操作.你很可能使用重新导入.

上一篇:SQL2 查找入职员工时间排名倒数第三的员工所有信息


下一篇:python – findspark.init()IndexError:列表索引超出范围错误