Haskell默认io缓冲



昨天我为我的学生写了一个小练习:制作一个反向回声程序。

为了学习新的东西,我尝试实施一个Haskell解决方案。琐碎的main = forever $ interact reverse不起作用。我浏览了这个问题并制作了一个更正版本:

import Control.Monad
import System.IO
 
main = forever $ interact revLines
 
revLines = unlines . map (reverse) . lines 

但是这个更正后的版本也不起作用。我阅读了缓冲文档并玩了各种设置。如果我设置NoBufferingLineBuffering,我的程序可以正常工作。最后,我打印出了标准输入和标准输出的默认缓冲模式。

import System.IO
main = do 
  hGetBuffering stdin >>= print 
  hGetBuffering stdout >>= print

如果我从 xinetd( echo "test" | nc localhost 7 ) 运行我的程序,我必须BlockBuffering Nothing,但从 cli 我得到了LineBuffering

  • 在缓冲方面,xinetd tcp 服务和 cli 程序有什么区别?
  • 如果我想用两种运行方法编写工作程序,我是否必须手动设置缓冲?
<小时 />

编辑:谢谢大家的有用答案。

接受烈焰给出的答案,他给了我一个暗示(3)。我再次浏览了 System.IO 文档并找到了hIsTerminalDevice功能,通过该功能我可以检查句柄的连接。

作为记录,这是我的最后一个程序:

{-# OPTIONS_GHC -W #-}
import System.IO
 
main = do
  hSetBuffering stdin LineBuffering
  hSetBuffering stdout LineBuffering
  
  interact revLines
 
revLines = unlines . map (reverse) . lines 

不是特定于Haskell的(例如,标准的C库做同样的事情)。传统上,如果文件描述符对应于终端,则缓冲设置为线路模式,否则设置为块模式。文件描述符类型可以通过isatty(3)函数检查 - 不确定它是否导出到System.IO

是的,如果您依赖它,则需要手动设置缓冲模式。

顺便说一下,您可以通过按cat | ./prog | cat运行程序来欺骗系统并在命令行中强制块缓冲。

GHC 运行时系统在选择默认缓冲时会尝试变得聪明。如果看起来标准输入和标准输出直接连接到终端,它们将被线路缓冲。如果它们看起来像是连接到其他东西,则它们是块缓冲的。如果要使用不是直接来自终端的逐行输入运行程序,这可能会有问题。例如,我认为cat | your-program的行为与your-program不同。

如果我想用两种运行方法编写工作程序,我是否必须手动设置缓冲?

是的。

相关内容

  • 没有找到相关文章