Raku에서 Proc :: Async의 버퍼링되지 않은 출력을 어떻게 차단합니까?
같은 스 니펫으로
# Contents of ./run
my $p = Proc::Async.new: @*ARGS; react { whenever Promise.in: 5 { $p.kill }
whenever $p.stdout { say "OUT: { .chomp }" } whenever $p.ready { say "PID: $_" } whenever $p.start { say "Done" }
}
같이 실행
./run raku -e 'react whenever Supply.interval: 1 { .say }'
나는 다음과 같은 것을 볼 것으로 예상했다
PID: 1234
OUT: 0
OUT: 1
OUT: 2
OUT: 3
OUT: 4
Done
그러나 대신 나는 본다
PID: 1234
OUT: 0
Done
나는 이것이 버퍼링과 관련이 있음을 이해합니다. 명령을 다음과 같이 변경하면
# The $|++ disables buffering ./run perl -E '$|++; while(1) { state $i; say $i++; sleep 1 }'
원하는 출력을 얻습니다.
나는 TTY IO :: Handle 객체가 unbuffered 라는 것을 알고 있으며 ,이 경우 $*OUT
생성 된 프로세스는 하나가 아닙니다. 그리고 IO :: Pipe 객체 는 "읽지 않은 쓰기가 즉시 차단되지 않도록"버퍼링된다는 것을 읽었습니다 (하지만 이것이 의미하는 바를 완전히 이해한다고 말할 수는 없지만).
그러나 내가 무엇을 시도 했든 상관없이 Proc :: Async의 버퍼링되지 않은 출력 스트림을 얻을 수 없습니다. 어떻게해야합니까?
열린 IO :: Handle을 사용하여 바인딩을 시도 $proc.bind-stdout
했지만 여전히 동일한 문제가 발생합니다.
$proc.bind-stdout: $*OUT
Proc :: Async 개체가 더 이상 버퍼링하지 않는다는 점에서 같은 작업 을 수행 하면 작동하지만 출력이 나가기 전에 출력을 활용할 수 없기 때문에 문제에 대한 해결책이 아닙니다. Proc :: Async를 버퍼링되지 않은 핸들에 바인딩 할 수 있다면 올바른 작업을 수행해야한다고 제안합니다. 그러나 나는 그것도 작동시킬 수 없었다.
설명 : Perl 예제에서 제안한대로 입력으로 전달할 명령에서 버퍼링을 비활성화하여이 문제를 해결할 수 있다는 것을 알고 있지만 Proc를 생성하는 쪽에서이 작업을 수행하는 방법을 찾고 있습니다. : Async 객체.
답변
Proc::Async
자체적으로 수신 된 데이터에 대해 버퍼링을 수행하지 않습니다. 그러나 생성 된 프로세스는 출력 대상에 따라 자체적으로 수행 될 수 있으며, 이것이 여기서 관찰되는 것입니다.
많은 프로그램은 출력 핸들이 TTY (터미널)에 연결되어 있는지 여부에 따라 출력 버퍼링 (색상 코드를 내보낼 지 여부 등)에 대한 결정을 내립니다. TTY는 사람이 출력을 볼 것이라는 것을 의미하므로 대기 시간이 처리량보다 선호되므로 버퍼링이 비활성화되거나 라인 버퍼링으로 제한됩니다. 반면에 출력이 파이프 또는 파일로 이동하는 경우 대기 시간이 그다지 중요하지 않으며 버퍼링을 사용하여 상당한 처리량을 달성하는 것으로 가정합니다 (데이터 쓰기를위한 시스템 호출이 훨씬 적음).
를 사용 Proc::Async
하여 무언가를 생성 할 때 생성 된 프로세스의 표준 출력은 TTY가 아닌 파이프에 바인딩됩니다. 따라서 호출 된 프로그램은이를 사용하여 출력 버퍼링을 적용할지 결정할 수 있습니다.
다른 종속성을 갖고 싶다면 다음을 통해 프로그램을 호출 할 수 있습니다. unbuffer
( expect
패키지의 일부인 것 같습니다) 와 같이 TTY를 위조 하는 것. 다음은 버퍼링 문제가있는 프로그램의 예입니다.
my $proc = Proc::Async.new: 'raku', '-e', 'react whenever Supply.interval(1) { .say }'; react whenever $proc.stdout {
.print
}
우리는 0
a 만보고 더 많은 출력을 위해 오랜 시간을 기다려야합니다. 다음을 통해 실행 unbuffer
:
my $proc = Proc::Async.new: 'unbuffer', 'raku', '-e', 'react whenever Supply.interval(1) { .say }'; react whenever $proc.stdout {
.print
}
매초마다 숫자가 출력되는 것을 의미합니다.
Raku가 언젠가 이에 대한 내장 솔루션을 제공 할 수 있을까요? 예- unbuffer
자체적으로 하는 "마법"을 수행함으로써 (나는 pty
일종의 가짜 TTY를 할당한다고 가정합니다 ). 이것은 사소한 것이 아닙니다-비록 libuv 개발자 들이 탐구하고 있지만 ; 적어도 MoarVM의 Rakudo가 진행되는 한, 그러한 기능을 제공하는 libuv 릴리스가 제공되는 순간, 우리는이를 노출시킬 것입니다.
.out-buffer
핸들 (예 : $*OUT
또는 $*ERR
)을 0 으로 설정할 수 있습니다 .
$ ./run raku -e '$*OUT.out-buffer = 0; react whenever Supply.interval: 1 { .say }'
PID: 11340
OUT: 0
OUT: 1
OUT: 2
OUT: 3
OUT: 4
Done