【问题标题】:OS environment variable reading in a spawned process在衍生进程中读取 OS 环境变量
【发布时间】:2019-02-02 06:30:37
【问题描述】:

这类似于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 产生的子进程使用不同的哈希种子?

【问题讨论】:

    标签: python multiprocessing python-multiprocessing


    【解决方案1】:

    您可以通过使用“fork”以外的其他启动方法来创建进程。您的操作系统正在使用 fork(您没有得到 PicklingError 来使用 lambda 作为目标)。

    您可以使用multiprocessing.set_start_method('spawn') 将启动方法更改为“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 毫秒
    • forkserver 289.83 毫秒
    • 产生 348.20 毫秒

    但这不一定与您的用例相关。

    【讨论】:

    • 注意:如果使用multiprocessing.Pool,而不是手动创建Process对象,惩罚应该少一些;当然,创建池仍然会花费更多,但工作进程被许多任务重用,而不是每个任务一个新的衍生进程。
    • 嗨@Darkonaut,我有一个关于在Windows 笔记本电脑here 上运行multiprocessing.Pool 的问题。我希望你能花一些时间来检查一下这个问题。非常感谢您的帮助!
    【解决方案2】:

    每个python 进程都在 OS 环境中启动,而multiprocessing 只有一个、共享和继承自父进程。

    【讨论】:

      猜你喜欢
      • 2012-10-29
      • 2011-12-10
      • 2016-10-20
      • 2019-06-08
      • 2016-11-27
      • 2018-03-09
      • 1970-01-01
      • 2022-07-29
      相关资源
      最近更新 更多