2012-11-29 34 views
4

我在这个网站上发现了一个问题,它向我展示了如何从Python调用Perl脚本。我目前使用下面的代码行来实现这一目标:从Python调用Perl脚本不断返回值

pipe = subprocess.Popen(["perl", "./Perl_Script.pl", param], stdout=subprocess.PIPE) 
result = pipe.stdout.read() 

此作品完美,但唯一的问题是,Perl脚本需要几分钟的时间来运行。在Perl脚本的结尾处,我使用一条简单的print语句来打印我需要返回的Python值,Python将其设置为Python中的结果结果

有没有办法让我的Perl脚本每隔几秒就可以包含更多的打印语句,可以连续返回到Python(而不是等待几分钟,并在最后返回一个长列表)?

最终,我在做的是使用Perl脚本来获取数据点,然后我发回到Python来绘制眼图。当Perl脚本完成运行时,我不想等待几分钟来绘制眼图,而是希望将数据段连续返回给Python,以便每隔几秒更新一次。

+0

您是否尝试过在perl脚本的中间阶段进行简单打印?我不明白问题是什么。 –

+0

是的,但python变量_result_不会更新,直到perl脚本完成运行。是的,我可以在perl脚本中放置更多的打印语句,并且这些语句会返回 - 但是当perl脚本完成时,它们会一起返回。 – dmranck

+0

下面有一个关于在推送到管道时关闭缓冲的答案,另一个关于确保你没有缓冲管道输入的答案。你需要做这两件事。 –

回答

1

你需要两件:要在Python的空间一次读取线和从Perl的一次发出一条线。第一可与环路来实现像

while True: 
    result = pipe.stdout.readline() 
    if not result: 
    break 
    # do something with result 

readline块,直到文本的行(或EOF)从附接的过程中接收,然后给你它读出的数据。只要每一块数据都在自己的路线上,那就应该有效。

但是,如果您在不修改Perl脚本的情况下运行此代码,您将不会获得任何输出,直到Perl脚本完成执行。这是因为默认情况下,Perl将块缓冲区输出到管道。你可以告诉它通过在你打印范围改变一个全局变量更频繁刷新缓冲区:

use English qw(-no_match_vars); 
local $OUTPUT_AUTOFLUSH = 1; 
print ...; 

http://perl.plover.com/FAQs/Buffering.htmlhttp://perldoc.perl.org/perlvar.html

+0

谢谢!正是我需要的。 – dmranck

2

默认的UNIX stdio缓冲区至少为8k。如果你写的小于8k,你最终会等到程序结束之前缓冲区被刷新。

告诉Perl程序停止缓冲输出,并可能告诉python不要通过管道缓冲输入。

$| = 1;

到非缓冲器STDOUT在你的Perl程序。

+0

默认情况下大多数unix工具(处理文本)是否行缓存? '猫 - '显示行为(每一行都立即刷新)。 – goncalopp

+1

如果您直接使用read()和write()系统调用,则执行无缓冲输出。如果使用stdio库,则使用缓冲IO,因为stdio在读/写之上实现缓冲。如果你想使用stdio函数,但没有缓冲,你必须使用函数调用来设置缓冲区的大小为0.我不知道cat是如何实现的,但stdio不像缓冲,但是提供了几个面向行的功能。但是一行被定义为一串文本,直到下一次出现行分隔符(在UNIX上默认为\ n,在Windows上默认为\ r \ n)。 –

+0

默认情况下,Perl对管道的STDOUT被块缓冲。请参阅http://perldoc.perl.org/perlvar.html中的$ OUTPUT_AUTOFLUSH。 – darch

1

pipe.stdout.read()尝试读取整个流,因此它将阻塞,直到perl完成。 试试这个:

line=' ' 
while line: 
    line = pipe.stdout.readline() 
    print line, 
+1

正确,但不完整。如果不解决用户的缓冲区痛苦,这将无济于事。 (见http://perl.plover.com/FAQs/Buffering.html) – darch

+0

'缓冲痛苦'需要成为模因。 –