Eof Perl 6 слишком быстро сдается?

В 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, который может дать мне одну строку ввода по мере ее поступления (возможно, из программы, которая медленно выводит строку с длинными паузами), но я полностью вернулся к этой простой проблеме. Я не нашел встроенного способа сделать это (что немного удивительно для такой распространенной задачи).


person brian d foy    schedule 01.11.2017    source источник


Ответы (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
  }
}
person Brad Gilbert    schedule 01.11.2017
comment
Я все еще хотел бы знать, что происходит с eof. - person brian d foy; 02.11.2017
comment
@briandfoy .eof возвращает True, если ввод находится в конце файла именно в тот момент, когда вызывается .eof (неблокирующий). Невозможно узнать, достигнут ли eof на TTY, пока он не закрыт. .get блокирует до \r \r\n \n и т. д. или до конца файла. Это означает, что TTY с большей вероятностью будет закрыт во время вызова .get, чем миллисекунды между вызовами .get. По сути, не используйте .eof так, как вы его используете. (Я научился этому с помощью Perl 5 по крайней мере 5 лет назад, хотя там это не проблема) - person Brad Gilbert; 03.11.2017
comment
Да, для TTY я ожидаю, что eof не вернет True, пока TTY не будет закрыт. - person brian d foy; 03.11.2017
comment
Этот ответ неверен, и в нем нет состояния гонки. .eof не вернет False до тех пор, пока не будет исчерпан и дескриптор входного файла, и буфер декодера. - person ; 04.11.2017
comment
@BradGilbert Nil, которое вы заметили, было связано с теперь исправленной ошибкой в ​​MoarVM - person ; 04.11.2017
comment
@ZoffixZnet Это на самом деле ломает его по-новому. Вместо того, чтобы, возможно, не возвращать True в конце файла, он возвращает True в конце строки, если вы используете интерактивный TTY. Единственный способ исправить это так, чтобы он работал как eof в Perl 5, это сделать его блочным (вероятно, не очень хорошая идея). - person Brad Gilbert; 04.11.2017