运行 来自 python 的程序多次初始化不同的 shell

Run a program from python several times whitout initialize different shells

我想要 运行 来自 Python 的编译 Fortran 数值模型。如果不在 Fortran 例程中实施几处更改,则使用 F2PY 编译它太复杂了。这就是为什么我只是使用 subprocess 模块调用它的可执行文件。

问题是我必须调用它几千次,而且我感觉生成太多 shell 会减慢整个过程。

我的实现(很难提供可重现的例子,对不起)看起来像:

import os
import subprocess

foo_path = '/path/to/compiled/program/'
program_dir = os.path.join(foo_path, "FOO")            #FOO is the Fortran executable
instruction = program_dir + " < nlst"                  #It is necesary to provide FOO a text file (nlst)
                                                       #with the configuration to the program

subprocess.call(instruction, shell=True, cwd=foo_path) #run the executable

运行 以这种方式(在循环内),它运行良好并且 FOO 生成一个文本文件输出,我可以从 python 中读取它。但我想做同样的事情来保持 shell 处于活动状态并只向其提供 "nlst" 文件路径。另一个不错的选择可能是启动一个空的 shell 并让它等待 instruction 字符串,它看起来像 "./FSM < nlst"。但是我不确定该怎么做,有什么想法吗?

谢谢!

[已编辑] 这样的事情应该有效,但 .comunicate 结束 process 并且第二次调用无效:

from subprocess import Popen, PIPE

foo_path = '/path/to/FOO/'
process = Popen(['bash'], stdin=PIPE, cwd=foo_path)
process.communicate(b'./FOO < nlst')

为了扩展我的评论,这里有一个使用您的代码进行线程化的示例:

import os
import subprocess
from concurrent.futures import ThreadPoolExecutor

foo_path = '/path/to/compiled/program/'
program_dir = os.path.join(foo_path, "FOO")            #FOO is the Fortran executable
instruction = program_dir + " < nlst"                  #It is necesary to provide FOO a text file (nlst)
                                                       #with the configuration to the program

def your_function():
    subprocess.call(instruction, shell=True, cwd=foo_path) #run the executable

# create executor object
executor = ThreadPoolExecutor(max_workers=4)  # uncertain of how many workers you might need/want

# specify how often you want to run the function
for i in range(10):
    # start your function as thread
    executor.submit(your_function)

我使用 pexpect 模块找到了这个解决方案,

import pexpect
import os.path

foo_path = '/path/to/FOO/'
out_path = '/path/to/FOO/foo_out_file'  #path to output file
child = pexpect.spawn('bash', cwd=foo_path)
child.sendline('./FOO < nlst')

while not os.path.exists(out_path): #wait until out_path is created
    continue

我在评论中的意思是类似于以下 Python 脚本:

from subprocess import Popen, PIPE

foo_path = '/home/ronald/tmp'
process = Popen(['/home/ronald/tmp/shexecutor'], stdin=PIPE, cwd=foo_path)

process.stdin.write("ls\n")
process.stdin.write("echo hello\n")
process.stdin.write("quit\n")

以及执行命令的shell脚本:

#!/bin/bash

while read cmdline; do
    if [ "$cmdline" == "quit" ]; then
        exit 0
    fi
    eval "$cmdline" >> x.output
done

您实际上可以做任何事情,而不是进行“评估”。 请注意,这只是实际实现的概要。 你需要做一些错误处理。如果你打算在生产环境中使用它,一定要将代码加固到极限。