简体   繁体   English

确保subprocess.Popen调用的执行顺序

[英]Ensuring order of execution for subprocess.Popen calls

I'm using subprocess.Popen to create an automated build script for the Scipy stack. 我正在使用subprocess.Popen为Scipy堆栈创建一个自动构建脚本。

My current process follows below. 我目前的流程如下。

mathbuild.json: mathbuild.json:

{"suitesparse": {"version": "4.2.1",
         "dependencies": ["metis"],
         "downloads": ["http://www.cise.ufl.edu/research/sparse/SuiteSparse/SuiteSparse-4.2.1.tar.gz"],
         "build": ["cd $DL_DIR",
               "tar xvfz SuiteSparse-4.2.1.tar.gz",
               "cd SuiteSparse",
               "cp -r $DL_DIR/metis-4.0.3 metis-4.0.3"]},

 "metis": {"version": "4.0.3",
       "dependencies": [],
       "downloads": ["http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/OLD/metis-4.0.3.tar.gz"],
       "build": ["cd $DL_DIR",
             "tar xvfz metis-4.0.3.tar.gz",
             "cd metis-4.0.3",
             "make"]}}

mathbuild.py: mathbuild.py:

def package_list(package, config):
    for dependency in config[package]['dependencies']:
        yield from package_list(dependency, config)
    yield package

def build_package(package, config):
    command = '; '.join(config[package]['build'])
    build = subprocess.Popen(command, shell=True)


def process_package(package, config, env_dir, dl_dir):
    print('INSTALLING {0}'.format(package))
    print('Downloading...')
    download_package(package, config, dl_dir)
    print('Building...')
    build_package(package, config)


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Install Pylab in a new venv.')
    parser.add_argument('env_dir', help='target directory for new environment')
    args = parser.parse_args()
    os.environ['ENV_DIR'], os.environ['DL_DIR'] = create_venv(args.env_dir)
    with open('mathbuild.json') as f:
        cfg = json.load(f)
    processed = []
    for package in package_list('suitesparse', cfg):
        if package not in processed:
            process_package(package, cfg,
                            os.environ['ENV_DIR'],
                            os.environ['DL_DIR'])
            processed += [package]

It creates a list of dependencies (such that later items depend on earlier ones) and then processes each one (downloading and then building based on the commands in the json file). 它创建一个依赖项列表(以便后面的项依赖于前面的项),然后处理每个项(下载然后根据json文件中的命令构建)。

The issue is that packages are being built via new subprocess.Popen calls before dependencies are fully built. 问题是在完全构建依赖项之前,通过新的subprocess.Popen调用构建了包。 In the above example, the suitesparse execution begins even before the metis build is done. 在上面的示例中,甚至在完成metis构建之前就开始执行suitesparse执行。 I assume that's because I'm opening a new subprocess each time around the for package in package_list('suitesparse', cfg) loop without regard for whether or not the prior subprocesses are done. 我假设这是因为我每次都for package in package_list('suitesparse', cfg)循环中打开一个新的子for package in package_list('suitesparse', cfg)而不考虑先前的子for package in package_list('suitesparse', cfg)是否完成。

The question What's the best way to synchronize the loop-based Popen calls so that each call starts only when the previous call to Popen (ie previous item in the list) is done? 问题什么是同步基于循环的Popen调用的最佳方法,以便每次调用仅在前一次调用Popen(即列表中的上一项)完成时启动?

What I've tried I've tried changing the loop so that it builds one combined Popen (with both package builds), but that seems hackish. 我尝试过我尝试改变循环,以便它构建一个组合的Popen(两个包构建),但这似乎是hackish。

It looks like you want subprocess.check_call() instead of Popen. 看起来你想要subprocess.check_call()而不是Popen。 From the docs : 来自文档

Run command with arguments. 使用参数运行命令。 Wait for command to complete. 等待命令完成。 If the return code was zero then return, otherwise raise CalledProcessError. 如果返回码为零则返回,否则引发CalledProcessError。

Your build function would look something like: 你的构建函数看起来像:

def build_package(package, config):
    command = '; '.join(config[package]['build'])
    subprocess.check_call(command, shell=True)

If you're actually using the Popen object, you can call the wait() method to wait for the subcommand to finish: 如果您实际使用的是Popen对象,则可以调用wait()方法等待子命令完成:

def build_package(package, config):
    command = '; '.join(config[package]['build'])
    build = subprocess.Popen(command, shell=True)
    # do something with the build object
    build.wait()
    # command is done

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM