多处理管理器似乎阻止了环境变量的变化

时间:2014-08-26 00:33:44

标签: python multiprocessing environment-variables python-behave

我使用表现来运行我们的基于小黄瓜的测试套件,其中一个自定义运行器可以并行处理运行行为。

这在我的本地(Windows 8.1)机器上完美运行,并允许我使用os.environ.update更改子进程中的环境变量

这在我们的Ubuntu 14.04服务器上失败,并且无法更改环境变量,这与每个要在其下运行的测试的数据库名称一致。有些人为我正在做的事情删除了代码:

def create_database(name):
    #create a postgres database, this works.    
    return "our_test_database_%s" % name

def drop_database(name):
    #drop a postgres database, also works
    return name

def get_features():
    return [feature for feature in os.listdir(features) if feature.endswith(".feature")

def main():
    manager = multiprocessing.Manager()
    databases = manager.Queue()
    cpu_count = multiprocessing.cpu_count()

    for i in range(cpu_count):
        databases.put(create_database(str(i)))

    pool = multiprocessing.Pool(processes=cpu_count, maxtaskperchild=1)
    results = pool.map(run_test, (feature, databases for feature in features), chunksize=1)

    while database = databases.get_nowait():
        drop_database(database)

def run_test(feature, databases):
    database = databases.get(block=True)
    os.environ.update({
        'DATABASE_URL': database
    })

    config = behave.configuration.Configuration(("--no-logcapture", "--tags=~@skip", "-f", "plain", feature))
    runner = behave.runner.Runner(config)
    failed = runner.run()

    databases.put(database)

在内部行为中,我们使用数据库来测试我们的Flask应用程序。 Flask在运行时无法找到设置的环境变量。

编辑:我不知道发生了什么变化,我们在服务器和我的机器上使用相同版本的Python,以及所有已知使用的软件包的相同版本。环境变量未正确更新,因此无法在以后的代码中访问。

2 个答案:

答案 0 :(得分:1)

嗯,您可以完全避免使用multiprocessing.Manager(),使用initializer multiprocessing.Pool关键字参数将普通multiprocessing.Queue传递给所有工作人员:

def main():
    databases = multiprocessing.Queue()
    cpu_count = multiprocessing.cpu_count()

    for i in range(cpu_count):
        databases.put(create_database(str(i)))

    pool = multiprocessing.Pool(processes=cpu_count, maxtasksperchild=1, 
                                initializer=init, initargs=(databases,))
    results = pool.map(run_test, features, chunksize=1)

    while database = databases.get_nowait():
        drop_database(database)

def init(dbs):
    global databases
    databases = dbs

def run_test(feature):
    database = databases.get(block=True)  # databases will be defined in the global namespace
    os.environ.update({
        'DATABASE_URL': database
    })

    config = behave.configuration.Configuration(("--no-logcapture", "--tags=~@skip", "-f", "plain", feature))
    runner = behave.runner.Runner(config)
    failed = runner.run()

这并不能真正解决Manager发生的任何事情,但会让你避免这个问题(假设Manager是真正的根本原因)。

答案 1 :(得分:0)

真正的问题出现在我的get_features()函数中。

使用的实际代码相当复杂,并且使用行为干运行来获取我的功能文件中所有未经过破坏的方案的列表。看似这个干运行进口了我们的烧瓶应用。

在Windows上,multiprocessing.Process不与父进程共享sys.modules空间,在linux上并非如此。当应用程序在父进程上下文中导入时,子进程都重用了导入和配置的flask应用程序。

这在https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods

中有记录

在Python3上,可以使用multiprocessing.set_start_method(' spawn')将其配置为在Linux上运行,而不是分叉。在Windows上,spawn是默认的,因此它在那里工作

然而,Python2没有这个选项,我正在寻找另一个解决方案来运行它并收集方案列表来运行