Python subprocess.call()在新创建的文件上调用gnuplot然后evince有时没有输出

时间:2018-02-01 16:40:21

标签: python subprocess gnuplot

我一直在尝试使用Python 3.4调用简单的gnuplot脚本,然后使用evince显示结果(.ps文件)。我的代码如下所示:

plotfile = "plot.p"

with open(plotfile, "w") as plt:
    lines = ['set term postscript',
             'set output "speed.ps"',
             'set xlabel "Time"',
             'set ylabel "Speed"',
             "plot '{}' u 2:4 title 'speed' with lines".format(infile)
            ]
    lines = map(lambda x: x + '\n', lines)
    plt.writelines(lines)

    # Call gnuplot and evince
    subprocess.call(['gnuplot', plotfile])
    subprocess.call(['evince', 'speed.ps'])

但是,evince通常不会显示该文件。我可以使用

正确创建文件
process = subprocess.Popen(['gnuplot', plotfile])  

但如果我尝试立即打开文件,请致电

process = subprocess.Popen(['gnuplot', plotfile])  
subprocess.Popen(['evince', plot.ps])

文件经常无法正确显示,我假设因为第一个命令没有及时完成。要解决此问题,我已尝试

process = subprocess.call(['gnuplot', plotfile])

process = subprocess.Popen(['gnuplot', plotfile])
process.wait() 

但是这两种情况都没有创建.ps文件。唯一可行(并非总是)的是

process = subprocess.Popen(['gnuplot', plotfile])  
time.sleep(1)
subprocess.Popen(['evince', plot.ps])

但这真的很难看。

所以我的问题是:

1)为什么等待进程完成(使用subprocess.call()wait())会阻止.ps文件被创建?
2)是否有一些解决方案不涉及使用“睡眠”?

版本:

  • CentOS 6.6
  • Python 3.4
  • Gnuplot 4.6
  • Evince 2.28.2

1 个答案:

答案 0 :(得分:2)

I believe you've had some misleading test results leading you down the wrong path. Using subprocess.call() or calling .wait() on a Popen object does genuinely wait for the program that was invoked to exit. What's not guaranteed, however, is whether the result of your plt.writelines() calls will be flushed to disk or will still be in an in-memory buffer by the time gnuplot is started.

Given the following code:

plotfile = "plot.p"

with open(plotfile, "w") as plt:
    lines = ['set term postscript',
             'set output "speed.ps"',
             'set xlabel "Time"',
             'set ylabel "Speed"',
             "plot '{}' u 2:4 title 'speed' with lines".format(infile)
            ]
    lines = map(lambda x: x + '\n', lines)
    plt.writelines(lines)

    plt.flush() ### <-- EITHER CALL THIS OR MOVE THE BELOW OUTSIDE THE with BLOCK

    # Call gnuplot and evince
    subprocess.call(['gnuplot', plotfile])
    subprocess.call(['evince', 'speed.ps'])

...absent the flush(), the plt file isn't guaranteed to have all contents flushed before subprocess.call() is invoked; lines can still be buffered and not available to other programs yet.

Closing a file flushes it, so moving the call()s outside the with block will also solve your problem.