这与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生成的子进程使用不同的散列种子?

最佳答案

您可以使用另一个start方法而不是“fork”来创建进程。您的操作系统正在使用fork(使用lambda作为目标不会得到PicklingError)。
您可以使用multiprocessing.set_start_method('spawn')将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 ms
forkserver 289.83毫秒
产生348.20毫秒
但这不一定与您的用例相关。

关于python - 在生成的过程中读取OS环境变量,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52044045/

10-12 18:21