【问题标题】:Does Perl 6's eof give up too quickly?Perl 6 的 eof 放弃得太快了吗?
【发布时间】:2017-11-01 01:04:36
【问题描述】:

在 Perl 5 中,我可以检查标准输入是否打开并从中读取一行。

for (;;) {
    last if eof(STDIN);
    print "Got line " . readline(STDIN);
    }

当我运行它并输入一行输入时,它会读取该行并在继续之前完成它的工作。程序不关心是否有长时间的停顿:

$ perl print-stdin.pl
this
Got line this
is
Got line is
a
Got line a
line
Got line line

如果我在 Perl 6 (Rakudo 2017.07) 中做同样的事情,程序会立即停止:

use v6;
loop {
    last if $*IN.eof;
    put "Got line " ~ $*IN.get;
    }

我真的很喜欢Supply,它可以在它到达时给我一行输入(可能来自一个缓慢输出行且有长时间停顿的程序),但我一直支持这个简单的问题。我没有找到执行此操作的内置方法(这对于如此常见的任务来说有点令人惊讶)。

【问题讨论】:

    标签: raku filehandle


    【解决方案1】:

    它似乎在最新版本上效果更好。
    尽管您所写的内容具有竞争条件,因为在调用 .eof 后可以关闭输入。这意味着它可能在 .get 被阻止时发生,因此它将返回 Nil。这将导致抛出警告,并打印额外的Got line 

    最好只使用来自.lines的迭代器

    for $*IN.lines { put "Got line $_" }
    

    或者使用.get的返回值来判断输入何时关闭。

    loop {
      with $*IN.get {
        put "Got line $_"
      } else {
        last
      }
    }
    

    如果您想从输入行中获取供应:

    $*IN.lines.Supply
    
    react {
      start whenever $*IN.lines.Supply {
        put "Got line $_";
        LAST done; # finish the outer 「react」 block when this closes
      }
      whenever Supply.interval(1) {
        put DateTime.now.hh-mm-ss
      }
    }
    
    22:46:33
    22:46:34
    a
    Got line a
    22:46:35
    22:46:36
    b
    Got line b
    22:46:37
    22:46:38
    c
    Got line c
    22:46:39
    22:46:40
    d
    Got line d
    22:46:41
    22:46:42
    ^D               # represents Ctrl+D
    

    上面需要start,因此它不会阻止Supply.interval(1) 供应正常启动。


    如果由于某种原因无法执行上述操作,您可以像这样创建供应:

    my \in-supply = supply {
    
      # 「await start」 needed so this won't block other things on this thread.
    
      await start loop {
        with $*IN.get { # defined (so still open)
    
          emit $_
    
        } else {        # not defined (closed)
    
          done;         # stop the Supply
    
          # last        # stop this loop (never reached)
    
        }
      }
    }
    
    react {
      whenever in-supply {
        put "Got line $_";
        LAST done # finish the outer 「react」 block when this closes
      }
      whenever Supply.interval(1) {
        put DateTime.now.hh-mm-ss
      }
    }
    

    【讨论】:

    • 我还是想知道eof的情况。
    • @briandfoy .eof 如果在调用 .eof 的确切时刻输入位于文件末尾(非阻塞),则返回 True。在关闭之前,无法知道 TTY 上是否达到了 eof。 .get 阻塞直到 \r \r\n \n 等或文件末尾。这意味着在调用.get 期间TTY 更有可能关闭,而不是调用.get 之间的毫秒。基本上不要以你使用它的方式使用.eof。 (我至少在 5 年前使用 Perl 5 学到了这一点,尽管那里的问题不大)
    • 是的,对于 TTY,我希望 eof 在 TTY 关闭之前不会返回 True。
    • 这个答案不正确,没有竞争条件。 .eof 不会返回 False,直到输入文件句柄已用尽并且解码器缓冲区已用尽。
    • @BradGilbert 你观察到的Nil 是由于a now-fixed bug in MoarVM
    猜你喜欢
    • 2022-01-12
    • 1970-01-01
    • 1970-01-01
    • 2011-08-06
    • 2016-11-08
    • 2017-08-14
    • 2019-05-11
    • 2012-01-04
    • 2020-02-16
    相关资源
    最近更新 更多