使用子流程自动重复执行计算密集型程序

Using subprocess to automate repeated executions of computationally intensive program

我想做什么

我正在使用一个名为 MESA (https://docs.mesastar.org/en/latest/index.html) 的程序,每个 运行 的相关步骤是:

  1. 在文本文件中编辑几行输入参数
  2. 执行(bash)shell命令“./mk”
  3. 执行(bash)shell命令“./rn”

成功完成 rn 之后,每次迭代都会重复这些步骤。

我的实现

为了自动执行这些步骤,我想出了以下程序:

import subprocess 

inputs[n][5] #2d array imported from csv

for i in range(len(inputs)):

    #read data
    with open('inlist', 'r', encoding='utf-8') as file:
            data = file.readlines()

    #lines to change
    data[ 73] = “   RSP_mass = ” + inputs[i][0] + “d0\n”
    data[ 74] = “   RSP_Teff = ” + inputs[i][1] + “d0\n”
    data[ 75] = “   RSP_L = ”+ inputs[i][2] + “d0\n”

    data[ 99] = “   log_directory = 'LOGS/” + inputs[i][3] + “'\n”
    data[100] = “   photo_directory = 'PHOTOS/” + inputs[i][4] + “'\n”

    #write data
    with open('inlist', 'r', encoding = 'utf-8') as file:
        file.writelines()

    #running MESA
    subprocess.run(“./mk”)
    subprocess.run(“./rn”, stdout = subprocess.PIPE)

问题 1:

由于 MESA 的计算量非常大(用完了所有可用的 16 个线程)并且每个 运行 已经占用了 2.5 - 3 小时,我非常担心可能出现的性能问题。由于每个 运行 的时间很长 运行,它也很难进行基准测试。

是否有我错过的更好的解决方案?

问题 2: 在 运行 MESA 向 stdout 输出略少于 1000 行,我认为如果通过子进程 运行ning 会导致相当慢的速度。最简单的方法当然是禁用任何输出,但是能够在 运行s 期间检查进化过程非常有用,所以我想尽可能保留它。从这个线程 ,我已经知道 stdout=subprocess.PIPE 是最快的方法。输出数据的存储已经由 MESA 自己处理。就性能而言,这是一个很好的解决方案吗?

问题 3: 这是最不重要的问题,但它可能会影响前面问题的实施,所以我想我也会问一下。是否可以定义一个自定义键盘中断,它不会立即终止程序,而是仅在下一个 运行 完成后才终止?基于线程How to generate keyboard events?,我认为键盘库最适合Ubuntu。

重复读取和重写输入文件是笨拙且低效的,而且在read-only模式下('r')打开它无论如何都无法写入它。

我会改为读取模板文件一次,然后根据它编写实际的配置文件。 (Python 有一个单独的 Template class in the standard library 可能值得研究,但这很简单,可以从头开始编写。)

一个子进程只是将 Python 完全排除在外,因此 运行 您来自 shell 的任务应该与 运行 来自 [=38] 的任务相同=].

如果你没有理由捕获进程的输出,就让它直接溢出到用户的终端上。在 subprocess 调用中不为 stdout=stderr= 指定任何内容可以实现这一点。

import subprocess 

# inputs[n][5] #2d array imported from csv

with open('template', 'r', encoding='utf-8') as file:
    data = file.readlines()

for inp in inputs:
    data[ 73] = f"   RSP_mass = {inp[0]}d0\n"
    data[ 74] = f"   RSP_Teff = {inp[1]}d0\n"
    data[ 75] = f"   RSP_L = {inp[2]}d0\n"

    data[ 99] = f"   log_directory = 'LOGS/{inp[3]}'\n"
    data[100] = f"   photo_directory = 'PHOTOS/{inp[4]}'\n"

    with open('inlist', 'w', encoding = 'utf-8') as file:
        file.writelines()

    subprocess.run("./mk", check=True)
    subprocess.run("./rn", check=True)

注意现在如何从名为 template 的文件中读取,一旦在循环之外,然后重复写入 ('w') 到 inlist。我还修复了循环,使其更加地道,并将卷曲双引号更改为正确的 ASCII 双引号。替换现在使用 f-strings 来提高易读性(恕我直言)。在接近尾声时,subprocess.runcheck=True 关键字参数指示 Python 在子进程失败时引发错误。

键盘中断的想法听起来很有挑战性。您可以添加一个信号处理程序以选择性地忽略某些信号,但更简单的解决方案是只检查循环中是否按下了任何常规键(或特定键;比如 q)。参见例如How to detect key presses?