在 Perl 中关闭打印缓冲区的魔术标点符号"$|"有哪些替代方案?



我正在重构一些旧代码(由其他人),我在一些CGI脚本的顶部发现了以下内容:

#Turn on output buffering
local $| = 1;
perlcritic像往常一样毫无帮助地指出了显而易见的:"使用了神奇的标点符号"。还有别的办法吗,还是perlcritic只是脾气暴躁?

进一步,仔细检查。我认为代码是错误的。

如果我没弄错的话,它的意思与注释所说的完全相反。它将关闭输出缓冲。我的记忆有点生疏了,而且我似乎找不到描述这个神奇标点符号的Perl文档。脚本在mod_perl中运行。

搅乱Perl的缓冲行为是否可取,是否会带来性能提升?大多数关于这方面的文章都是在21世纪头十年的早期写的。这仍然是一个有效的良好实践吗?

$|是真正按文件句柄指定的标点符号变量之一。变量获取或设置当前选择的输出文件句柄的值(默认情况下为STDOUT)。($.略有不同;它被绑定到最后读取的文件句柄。)

访问这些文件的"现代"方式是通过文件句柄上的方法:

use IO::Handle;
$fh->autoflush(1);  # instead of $|=1

每个变量对应的方法记录在perldoc perlvar.

你的问题似乎有点散乱,但我会尽力回答得彻底。

你想读perldoc pervar。相关部分说:

   $|      If set to nonzero, forces a flush right away and after every write or print on the currently selected output channel.  Default is 0
           (regardless of whether the channel is really buffered by the system or not; $| tells you only whether you've asked Perl explicitly to
           flush after each write).  STDOUT will typically be line buffered if output is to the terminal and block buffered otherwise.  Setting this
           variable is useful primarily when you are outputting to a pipe or socket, such as when you are running a Perl program under rsh and want
           to see the output as it's happening.  This has no effect on input buffering.  See "getc" in perlfunc for that.  See "select" in perldoc
           on how to select the output channel.  See also IO::Handle. (Mnemonic: when you want your pipes to be piping hot.)

所以,是的,评论是不正确的。设置$| = 1确实使禁用缓冲,而不是打开

至于性能,默认情况下启用输出缓冲的原因是因为这样可以提高性能——即使在2011年——并且可能直到时间结束,除非量子I/O以某种方式完全改变了我们理解I/O的方式。

禁用输出缓冲的原因不是为了提高性能,而是为了以牺牲性能为代价改变其他行为

因为我不知道你的代码做什么,我不能推测它想要禁用输出缓冲的原因。

禁用输出缓冲的一些(但不是全部)可能的原因:

  • 你正在写一个套接字或管道,而另一端期望立即响应。
  • 您正在向控制台写入状态更新,并希望用户立即看到它们,而不是在一行的末尾。当您在许多操作等之后输出一个周期时,这尤其常见。
  • 对于CGI脚本,您可能希望浏览器在处理完成之前显示一些HTML输出。

这个评论,正如其他人所说,是不正确的。相比之下,local $| = 1禁用输出缓冲。

要遵守Perl::Critic的政策,您可以使用English模块:

use English qw( -no_match_vars );
local $OUTPUT_AUTOFLUSH = 1;  # equivalent to: local $| = 1

正如您可以在手册中检查的那样,$|=1关闭缓冲,表示必须刷新缓冲区是真的,因此注释是错误的。

关于它是好还是不好,我不知道,但我也看到,总是在CGI脚本中完成,所以我怀疑这是一件好事,在这种特殊情况下,也许是因为通常CGI脚本想要使数据可用,一旦他们写。