从 Python 调用写入文件的程序 - 我可以避免 IO 吗?
Call a program from Python that writes to a file - Can I avoid the IO?
在 python 中,可以使用(例如)subprocess.Popen
到 运行 程序并根据需要重定向 stdout 或 stderr,以便您可以处理输出。
你能用直接写入文件的调用程序来做到这一点吗?
我有一个将结果写入文件的 Fortran 程序(它还将中间结果写入文件)。现在,我从 Python (2.7) 调用这个程序,等待它完成,然后读取输出文件。
但我必须经常并行地执行此操作,并且 I/O 占用了 运行 时间的很大一部分。
在不修改直接写入文件(不是 stdout)的 fortran 程序的情况下,我能否以某种方式直接从 python 捕获 I/O,避开写入磁盘?
在不修改 Fortran 程序的情况下执行此操作的最简单方法可能是使用 named pipes - 与管道相同的想法,但持久(不依赖于任何一个进程)并且通过文件系统可见。
假设我们有一个简单的 Fortran 程序:
program writer
integer,parameter :: u=10
integer :: i
real :: x
open(u,file='output.dat')
do i=1,10
x = (i-1)*0.5
write(u,*) i, x, x**2, x**3
end do
close(u)
end program writer
其中,当 运行 时,提供所需的输出:
1 0.000000 0.000000 0.000000
2 0.5000000 0.2500000 0.1250000
3 1.000000 1.000000 1.000000
4 1.500000 2.250000 3.375000
5 2.000000 4.000000 8.000000
6 2.500000 6.250000 15.62500
7 3.000000 9.000000 27.00000
8 3.500000 12.25000 42.87500
9 4.000000 16.00000 64.00000
10 4.500000 20.25000 91.12500
我们知道输出文件将是 output.dat
(因为它是硬编码的,或者作为选项提供)。
我们可以创建一个名为 output.dat 的命名管道并从另一个程序读取它,它的行为就像我们将现有 Fortran 程序的输出通过管道传输到另一个命令一样 - 即使 Fortran 程序没有写入 stdout 或 stderr:
$ rm output.dat
$ mkfifo output.dat
$ awk '{print "Got line: ",[=12=]}' < output.dat &
[1] 69609
$ ./writer
$ Got line: 1 0.000000 0.000000 0.000000
Got line: 2 0.5000000 0.2500000 0.1250000
Got line: 3 1.000000 1.000000 1.000000
Got line: 4 1.500000 2.250000 3.375000
Got line: 5 2.000000 4.000000 8.000000
Got line: 6 2.500000 6.250000 15.62500
Got line: 7 3.000000 9.000000 27.00000
Got line: 8 3.500000 12.25000 42.87500
Got line: 9 4.000000 16.00000 64.00000
Got line: 10 4.500000 20.25000 91.12500
[1]+ Done awk '{print "Got line: ",[=12=]}' < output.dat
$ rm output.dat
太棒了 - 我们刚刚让写入程序写入(据其所知)它的文件,然后我们 awk
从该文件逐行读取,就像它出现的那样。
所以现在我们可以在 Python:
中进行启动和读取
import os
import subprocess
if __name__ == "__main__":
outfilename = "output.dat"
os.mkfifo(outfilename,0777)
i = []
x = []
xsquared = []
writer = subprocess.Popen( "./writer" )
with open(outfilename,'r') as fortranoutput:
for line in fortranoutput:
items=line.split()
i.append(int(items[0]))
x.append(float(items[1]))
xsquared.append(float(items[2]))
print "Got: i = ", i
print " x = ", x
print " x^2= ", xsquared
而 运行ning 给出:
$ python readFifo.py
Got: i = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
x = [0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5]
x^2= [0.0, 0.25, 1.0, 2.25, 4.0, 6.25, 9.0, 12.25, 16.0, 20.25]
在 python 中,可以使用(例如)subprocess.Popen
到 运行 程序并根据需要重定向 stdout 或 stderr,以便您可以处理输出。
你能用直接写入文件的调用程序来做到这一点吗?
我有一个将结果写入文件的 Fortran 程序(它还将中间结果写入文件)。现在,我从 Python (2.7) 调用这个程序,等待它完成,然后读取输出文件。
但我必须经常并行地执行此操作,并且 I/O 占用了 运行 时间的很大一部分。
在不修改直接写入文件(不是 stdout)的 fortran 程序的情况下,我能否以某种方式直接从 python 捕获 I/O,避开写入磁盘?
在不修改 Fortran 程序的情况下执行此操作的最简单方法可能是使用 named pipes - 与管道相同的想法,但持久(不依赖于任何一个进程)并且通过文件系统可见。
假设我们有一个简单的 Fortran 程序:
program writer
integer,parameter :: u=10
integer :: i
real :: x
open(u,file='output.dat')
do i=1,10
x = (i-1)*0.5
write(u,*) i, x, x**2, x**3
end do
close(u)
end program writer
其中,当 运行 时,提供所需的输出:
1 0.000000 0.000000 0.000000
2 0.5000000 0.2500000 0.1250000
3 1.000000 1.000000 1.000000
4 1.500000 2.250000 3.375000
5 2.000000 4.000000 8.000000
6 2.500000 6.250000 15.62500
7 3.000000 9.000000 27.00000
8 3.500000 12.25000 42.87500
9 4.000000 16.00000 64.00000
10 4.500000 20.25000 91.12500
我们知道输出文件将是 output.dat
(因为它是硬编码的,或者作为选项提供)。
我们可以创建一个名为 output.dat 的命名管道并从另一个程序读取它,它的行为就像我们将现有 Fortran 程序的输出通过管道传输到另一个命令一样 - 即使 Fortran 程序没有写入 stdout 或 stderr:
$ rm output.dat
$ mkfifo output.dat
$ awk '{print "Got line: ",[=12=]}' < output.dat &
[1] 69609
$ ./writer
$ Got line: 1 0.000000 0.000000 0.000000
Got line: 2 0.5000000 0.2500000 0.1250000
Got line: 3 1.000000 1.000000 1.000000
Got line: 4 1.500000 2.250000 3.375000
Got line: 5 2.000000 4.000000 8.000000
Got line: 6 2.500000 6.250000 15.62500
Got line: 7 3.000000 9.000000 27.00000
Got line: 8 3.500000 12.25000 42.87500
Got line: 9 4.000000 16.00000 64.00000
Got line: 10 4.500000 20.25000 91.12500
[1]+ Done awk '{print "Got line: ",[=12=]}' < output.dat
$ rm output.dat
太棒了 - 我们刚刚让写入程序写入(据其所知)它的文件,然后我们 awk
从该文件逐行读取,就像它出现的那样。
所以现在我们可以在 Python:
中进行启动和读取import os
import subprocess
if __name__ == "__main__":
outfilename = "output.dat"
os.mkfifo(outfilename,0777)
i = []
x = []
xsquared = []
writer = subprocess.Popen( "./writer" )
with open(outfilename,'r') as fortranoutput:
for line in fortranoutput:
items=line.split()
i.append(int(items[0]))
x.append(float(items[1]))
xsquared.append(float(items[2]))
print "Got: i = ", i
print " x = ", x
print " x^2= ", xsquared
而 运行ning 给出:
$ python readFifo.py
Got: i = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
x = [0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5]
x^2= [0.0, 0.25, 1.0, 2.25, 4.0, 6.25, 9.0, 12.25, 16.0, 20.25]