실행중인 프로그램에서 출력 버퍼 플러시 강제


20

정기적으로 데이터를 표준 출력으로 출력하는 장기 실행 파이썬 스크립트가 있습니다.

python script.py > output.txt

이 스크립트는 잠시 동안 실행되어 왔으며 Ctrl+ 로 중지하고 C싶지만 출력을 잃지 않습니다. 불행히도 스크립트를 구현할 때 sys.stdout.flush()( 출력 플러싱을 강제하기위한 이전에 제안 된 솔루션) 과 같은 각 출력 라인 후에 버퍼를 플러시하는 것을 잊었 으므로 Ctrl+ 를 호출 C하면 모든 출력이 손실됩니다.

실행중인 파이썬 스크립트 (또는 일반적으로 실행중인 프로세스)와 상호 작용하여 출력 버퍼를 플러시 할 수있는 방법이 있는지 궁금한 경우. 스크립트를 올바르게 플러시하기 위해 스크립트를 편집하고 다시 실행하는 방법을 묻지 않습니다.이 질문은 실행중인 프로세스와의 상호 작용에 관한 것입니다 (제 경우에는 현재 코드 실행에서 출력이 손실되지 않습니다).

답변:


18

경우 하나가 진정으로 데이터를 원했다, 나는 부착 좋을 것 gdb를 호출, 파이썬 인터프리터에 디버거를 잠시 작업을 중단 fsync(1)( 표준 출력 (과정을 다시 시작) 그것에서) 분리 및 출력 파일 정독 이동합니다.

에서 봐 /proc/$(pidof python)/fd유효한 파일 기술자를 볼 수 있습니다. $(pidof x)' x' 프로세스의 PID를 반환합니다 .

# your python script is running merrily over there.... with some PID you've determined.
#
# load gdb
gdb
#
# attach to python interpreter (use the number returned by $(pidof python))
attach 1234
#
# force a sync within the program's world (1 = stdout, which is redirected in your example)
call fsync(1)
#
# the call SHOULD have returned 0x0, sync successful.   If you get 0xffffffff (-1), perhaps that wasn't stdout.  0=stdin, 1=stdout, 2=stderr
#
# remove our claws from poor python
detach
#
# we're done!
quit

이 방법을 사용하여 작업 디렉토리를 변경하고 설정을 즉시 조정할 수 있습니다 ... 많은 것들. 아아, 실행중인 프로그램에 정의 된 함수 만 호출 할 수 fsync있지만 훌륭하게 작동합니다.

(gdb 명령 ' info functions'은 사용 가능한 모든 기능을 나열합니다.주의하십시오. 프로세스에서 라이브 를 운영 하고 있습니다.)

프로세스의 버퍼에 무엇이 숨겨져 있는지 확인할 수 있는 명령 peekfd( psmiscDebian Jessie 및 기타 패키지에 있음)도 있습니다. 다시, /proc/$(pidof python)/fdpeekfd에 인수로 제공 할 유효한 파일 디스크립터가 표시됩니다.

-u파이썬을 기억하지 못하는 경우 , 항상 명령에 stdbuf(in coreutils, 이미 설치됨) 접두어 stdin / stdout / stderr를 버퍼링되지 않은, 라인 버퍼링 또는 블록 버퍼링으로 설정하십시오 :

stdbuf -i 0 -o 0 -e 0 python myscript.py > unbuffered.output

물론, man pages친구들이여, 안녕! 아마도 별명도 여기에 유용 할 것입니다.

alias python='python -u'

이제 파이썬은 항상 -u모든 명령 줄 노력에 사용합니다!


5

먼저 파이썬 (또는 적어도 glibc)에 대한 디버깅 심볼이 있는지 확인하십시오. 에 페도라 (1) 당신이 그들을 함께 설치할 수 있습니다 :

dnf debuginfo-install python

그런 다음 gdb 를 실행중인 스크립트에 첨부 하고 다음 명령을 실행하십시오.

[user@host ~]$ pidof python2
9219
[user@host ~]$ gdb python2 9219
GNU gdb (GDB) Fedora 7.7.1-13.fc20
...
0x00007fa934278780 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:81
81  T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
(gdb) call fflush(stdout)
$1 = 0
(gdb) call setvbuf(stdout, 0, 2, 0)
$2 = 0
(gdb) quit
A debugging session is active.

    Inferior 1 [process 9219] will be detached.

Quit anyway? (y or n) y
Detaching from program: /usr/bin/python2, process 9219

이것은 stdout 을 비우고 버퍼링도 비활성화합니다. 2로부터 setvbuf호출의 값입니다 _IONBF내 시스템에. 당신의 것이 무엇인지 알아 내야합니다 ( grep _IONBF /usr/include/stdio.h트릭을해야합니다).

CPython 2.7 구현 PyFile_SetBufSizePyFile_WriteStringCPython 2.7에서 본 내용에 따르면 꽤 잘 작동하지만 보장 할 수는 없습니다.


1 Fedora에는 debuginfo rpms 라는 특별한 유형의 RPM이 포함되어 있습니다. 이러한 자동 생성 RPM에는 프로그램 파일의 디버깅 정보가 포함되어 있지만 외부 파일로 이동되었습니다.


나는 파이썬 2.7을 시도하고 같은 결과를 얻었습니다. 게시 한 디버깅 업데이트를 살펴 보겠습니다.
DarkHeart

가치있는 것에 대해, CPython 3.52.7 과 다른 I / O ( fileobject.c) 구현을 가진 것으로 보입니다 . 누군가 모듈 을 파헤쳐 야 합니다. io
Cristian Ciupitu

@DarkHeart, 당신은 같은 간단한 프로그램을 먼저 테스트 할 수 있습니다 이것 .
Cristian Ciupitu

4

즉각적인 문제에 대한 해결책은 없습니다. 스크립트가 이미 시작된 경우 사실 후에 버퍼링 모드를 변경할 수 없습니다. 이들은 모두 메모리 내 버퍼이며 스크립트가 시작되고 파일 핸들이 열리고 파이프가 생성 될 때 설정됩니다.

롱샷으로서, 문제의 버퍼링 중 일부 또는 전부가 출력의 IO 레벨에서 수행되는 경우에만 sync명령을 수행 할 수 있습니다 . 그러나 이것은 일반적으로 이와 같은 경우에는 거의 없습니다.

앞으로 파이썬의 -u옵션 * 를 사용 하여 스크립트를 실행할 수 있습니다. 일반적으로 많은 명령에는 stdin / stdout 버퍼링을 비활성화하는 명령 별 옵션이 unbuffer있으며 expect패키지 의 명령으로 일반적인 성공을 거둘 수도 있습니다 .

Ctrl+는 C시스템 수준의 버퍼가 프로그램이 중단 될 때 플러시 될 원인이 되지 않는 버퍼링이 파이썬에 의해 수행되고 그와 함께 자신의 버퍼를 플러시하는 논리를 구현하지 않은 Ctrl+ C. 일시 중단, 충돌 또는 종료는 그렇게 친절하지 않습니다.

* 강제 stdin, stdout와 stderr에게 버퍼가 될 수 있습니다.


2

Python 2.7.7 문서, "Python Setup and Usage", 하위 섹션 1. 명령 행 및 환경 은이 Python 인수를 설명합니다.

-유

stdin, stdout 및 stderr이 완전히 버퍼링되지 않도록하십시오. 중요한 시스템에서는 stdin, stdout 및 stderr을 이진 모드로 설정하십시오.

file.readlines () 및 File Objects (sys.stdin의 행)에 내부 버퍼링이 있으며이 옵션의 영향을받지 않습니다. 이 문제를 해결하려면 while 1 : 루프 내에서 file.readline ()을 사용하십시오.

또한이 환경 변수 :

피토 논 부퍼

이것이 비어 있지 않은 문자열로 설정되면 -u 옵션을 지정하는 것과 같습니다.


1
고마워-하지만이 둘 다 파이썬 스크립트를 처음 실행할 때 지정 해야하는 옵션처럼 들립니다. 실행중인 스크립트로 출력을 덤프하는 방법이 있는지 궁금합니다.
josliber 2018 년

데이터가 아마도 어딘가에 메모리 버퍼에 있기 때문에 그러한 해결책이 있다고 생각하지 않습니다. 버퍼가 어디에 있고 어떻게 쓰는지 알 수있을 정도로 실행 파일을 잘 알고있는 dll을 파이썬에 주입해야합니다. 나는 대부분의 사람들이 위의 두 가지 방법 중 하나를 사용한다고 생각합니다. 결국 환경 변수를 추가하는 것은 다소 쉽습니다.
harrymc 2016 년

해결 방법이 없을 수도 있습니다. 내 질문에 언급했듯이, 파이썬에서 버퍼를 플러시하는 방법을 알고 sys.stdout.flush()있지만 ( -u옵션을 사용 했지만 옵션이 훨씬 쉬워 보입니다) 코드를 호출 할 때 잊어 버렸습니다. 일주일 이상 내 코드를 이미 실행 한 후 다른 주 동안 코드를 다시 실행할 필요없이 출력을 얻을 수있는 방법이 있기를 바랍니다.
josliber 2014 년

데이터가 어떻게 생겼는지 아는 경우, 광범위하게 가져온 방법은 Process Explorer를 사용하여 프로세스 의 전체 메모리 덤프를 가져온 다음 파일에서 문자열을 검색하는 것입니다. 이렇게하면 프로세스가 종료되지 않으므로 다른 방법을 시도해 볼 수 있습니다.
harrymc

나는 리눅스에있다-그 소프트웨어와 동등한 리눅스가 있는가?
josliber 2016 년

2

Ctrl-C를 실행 한 후 버퍼 출력으로 인해 손실되는 것에 대해 너무 신중한 것 같습니다. 이 게시물 에 따르면 프로그램에 정상적인 종료가 있으면 버퍼가 플러시 될 것으로 예상해야합니다 .Ctrl-C를 누르는 경우입니다. 반면에 SIGKILL 또는 이와 유사한 스크립트를 종료하면 버퍼링 된 출력이 손실됩니다.


찾으려면 시도해야합니다. Ctrl-C를 사용하면 하위 수준 IO 버퍼가 플러시됩니다. 파이썬이 자체 버퍼링을 수행하는 경우 Ctrl-C는 파이썬이 논리를 구현하기에 충분할 경우에만 플러시합니다. 바라건대 파이썬은 바퀴를 재발 명하지 않기로 결정했고 시스템의 정상적인 버퍼링 수준에 의존합니다. 나는 그것이 사실인지 전혀 모른다. 그러나 경고하십시오.
Jason C

OS는 프로그램의 메모리 공간에있는 내용을 플러시 할 수 없습니다. 플러시되는 것은 시스템 메모리의 데이터입니다. 즉, 시스템 호출을 사용하여 프로그램에 의해 이미 작성된 데이터를 의미합니다. 오류 종료의 경우 이러한 시스템 버퍼도 삭제됩니다. 요컨대, 파이썬으로 아직 작성되지 않은 데이터는 플러시 될 수 없으며 모든 경우에 손실됩니다.
harrymc 2016 년

0

또 다른 가능한 해결책은 코어 덤프로 프로세스를 강제 종료 한 다음 사후 메모리 내용을 분석하는 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.