生成过程中的OS环境变量读取

时间:2018-08-27 17:12:34

标签: python python-multiprocessing

这与a previous question类似,但对于multiprocessing而不是subprocess。与PYTHONHASHSEED不同,使用multiprocessing时动态更改subprocess似乎无效:

#check_environ.py
import os, multiprocessing, subprocess, sys

s = 'hello'
print('parent', os.getenv('PYTHONHASHSEED'), hash(s))

if len(sys.argv) > 1:
    os.environ['PYTHONHASHSEED'] = sys.argv[1]
subprocess.call(['python', '-c', "import os;print('subprocess', os.getenv('PYTHONHASHSEED'), hash('{}'))".format(s)])
multiprocessing.Process(target=lambda:print('multiprocessing', os.getenv('PYTHONHASHSEED'), hash(s))).start()

示例运行:

# explicit PYTHONHASHSEED for subprocess/multiprocessing 
$ python check_environ.py 12

parent None 4472558296122225349
subprocess 12 -8207222429063474615
multiprocessing 12 4472558296122225349

# random PYTHONHASHSEED for subprocess/multiprocessing 
$ python check_environ.py

parent None 7990499464460966677
subprocess None 1081030409066486350
multiprocessing None 7990499464460966677

因此,无论如何,multiprocessing哈希使用与父代相同的种子。是否有一种方法可以强制multiprocessing生成的子进程使用其他哈希种子?

2 个答案:

答案 0 :(得分:1)

您可以通过使用除'fork'之外的其他启动方法来创建流程。您的操作系统正在使用fork(将lambda用作目标不会得到PicklingError)。

您可以使用multiprocessing.set_start_method('spaw')将start方法更改为“ spawn”(在Windows上是默认选项,并且是唯一选项),如果可用,也可以更改为“ forkserver”。使用multiprocessing.get_all_start_methods()获取所有可用方法。

#check_environ.py
import sys, os, subprocess
import multiprocessing as mp


def show(s):
    print('multiprocessing', os.getenv('PYTHONHASHSEED'), hash(s))


if __name__ == '__main__':

    mp.set_start_method('spawn')

    s = 'hello'
    print('parent', os.getenv('PYTHONHASHSEED'), hash(s))

    if len(sys.argv) > 1:
        os.environ['PYTHONHASHSEED'] = sys.argv[1]

    cmd = "import os; " \
          "print('subprocess', os.getenv('PYTHONHASHSEED'), hash('{}'))"
    subprocess.call(['python', '-c', cmd.format(s)])
    p = mp.Process(target=show, args=(s,))
    p.start()
    p.join()

终端输出:

$ python check_environ.py 12

parent None 4279361553958749032
subprocess 12 -8207222429063474615
multiprocessing 12 -8207222429063474615

如果需要多次在启动方法之间切换,请使用上下文对象设置启动方法:

ctx = mp.get_context('spawn')
p = ctx.Process(target=foo, args=(var,))

但是准备好使用fork以外的其他启动方法付出巨大的时间损失。我对运行Ubuntu 18.04的计算机上的python进程进行了以下测试:

  • 叉形1.59毫秒
  • 叉车289.83毫秒
  • 产生348.20毫秒

但这与您的用例无关。

答案 1 :(得分:0)

每个python进程都是在操作系统环境中启动的,而在multiprocessing情况下,只有一个被共享,并从父进程继承。