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