处理后将外部程序的输出传回给它

2024-03-28 18:29:46 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个Fortran代码,它将一个文件作为输入,并将输出写入stdout。为了避免读/写周期,我想在python中运行代码并将输出转换成numpy数组。我可以使用以下函数执行此操作:

def run_fortran(infile):

    import subprocess
    import numpy as np

    cmd = ['./output.e', infile]
    p = subprocess.Popen(cmd, stdout = subprocess.PIPE)
    out, err = p.communicate()

    if p.returncode == 0: 
        return np.array(out.split(),dtype=int)

现在我获取数组,修改它并将其写入一个文件。新文件再次传递到run_fortran(infile)。我是否可以避免这一步,以某种方式使用run_fortran的输出而不是传递文件名?你知道吗

我试了两个案子都没有成功:

(1)转换为字符串

arr = run_fortran('input.txt')
new_arr = str(arr).replace("[","").replace("]","")
run_fortran(new_arr)

这将返回一个空数组。你知道吗

(2)使用StringIO转换为文件类型对象:

from cStringIO import StringIO
run_fortran(StringIO(new_arr))

这将返回一个错误:TypeError: execv() arg 2 must contain only strings,这是有意义的。你知道吗


Tags: 文件run代码importnumpycmdnewnp
2条回答

在fortran中,read(*,*)read(5,*)read*,语句将从标准输入中读取,如果格式正确,它将工作。如果您处理的是formatted数据,即任何人类可读的数据,而不是二进制文件,那么您可能需要一个读循环,如:

do line=1,numlines
  read(*,*) array(line,:)
enddo

不需要openclose语句。因此,如果您正在向文件写入的内容是直接传递的,那么您应该能够删除这些语句,并将文件unit更改为5*。你知道吗

现在有更有效的方法来进行这种沟通,但任何解决方案都是一个很好的解决方案,如果它适合你的目的。你知道吗

如果您的Fortran程序(即'./output.e'AFAICS)可以从stdin读取,而不仅仅是从常规文件读取,那么您可以通过传递它stdin=subprocess.PIPEother valid values are“一个现有的文件描述符(一个正整数)[或]一个现有的文件对象”)而不需要临时文件。在UNIX中,总是有/dev/stdin放在命令行上,而在Windows中,总是有con。你知道吗

不过,如果由于处理的性质,程序只能在“会话”中工作(即不能连续运行并在可用时提供新数据),则必须重复调用它。你知道吗

请注意,您必须在不同的线程中处理不同的管道,以避免死锁。因此,要么使用^{}(但是程序不能连续运行),要么手动生成一个stdout/stderr线程(这就是communicate()所做的;不要stdin,因为输出读取代码必须在开始写入stdin时运行,否则外部程序在写入时可能会因“设备上没有空间”而阻塞)。你知道吗

下面是连续运行程序的示例代码:

p=subprocess.Popen(argv,stdin=subprocess.PIPE,stdout=subprocess.PIPE)
while True:
    #the only more elegant way to return a value from a thread is with a Thread subclass,
    # see http://stackoverflow.com/questions/6893968/how-to-get-the-return-value-from-a-thread-in-python
    output_container=[]
    ot=threading.Thread(target=_outputreaderthread,args=(p.stdout,output_container,data))
    ot.start()
    p.stdin.write(data)
    ot.join()
    output=output_container[0]

    data=process_output(output)
    if no_more_processing_needed(data): break
p.stdin.close()
if p.wait()!=0:raise subprocess.CalledProcessError(p.returncode,argv)

def _outputreaderthread(stream,container,data):
    #since there's no process termination as an end mark here,
    # you need to read exactly the right number of bytes to avoid getting blocked.
    #use whatever technique is appropriate for your data (e.g. readline()'s)
    output=stream.read(calculate_output_size(data))
    container.append(output)

相关问题 更多 >