web-dev-qa-db-ja.com

実行中のプログラムで出力バッファを強制的にフラッシュする

私は長期実行のpythonスクリプトを使用して、次のようなもので呼び出した標準出力に定期的にデータを出力します:

_python script.py > output.txt
_

このスクリプトはしばらく実行されており、停止したい Ctrl+C ただし、出力は失われません。残念ながら、スクリプトを実装したときに、sys.stdout.flush()以前に提案された 出力のフラッシュを強制するためのソリューション)などの出力行ごとにバッファをフラッシュするのを忘れていたため、 Ctrl+C 今のところ、すべての出力が失われます。

実行中のpythonスクリプト(または、より一般的には、実行中のプロセス)とやり取りして、出力バッファーを強制的にフラッシュさせる方法があるかどうか疑問に思っています。編集方法や、スクリプトを再実行して、正しくフラッシュするようにします。この質問は、特に実行中のプロセスとの対話に関するものです(私の場合、現在のコード実行からの出力が失われることはありません)。

21
josliber

Ctrl-Cを実行した後、バッファリングされた出力が失われることについて私は過度に用心していたようです。 この投稿 によると、プログラムに通常の終了がある場合は、バッファがフラッシュされることを期待する必要があります。これは、Ctrl-Cを押した場合に当てはまります。一方、SIGKILLなどでスクリプトを強制終了すると、バッファリングされた出力が失われます。

2
josliber

[〜#〜] if [〜#〜]本当にそのデータを必要としていた場合、gdbデバッガからpythonインタプリタ、タスクを一時的に停止してfsync(1)stdoutを呼び出す) )、そこから切り離し(プロセスを再開)、出力ファイルを熟読します。

/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
_

私はこの方法を使用して、作業ディレクトリ、Tweak設定をその場で変更しました...多くのもの。残念ながら、実行中のプログラムで定義されている関数のみを呼び出すことができますが、fsyncは適切に機能します。

(gdbコマンド '_info functions_'は、利用可能なすべての関数を一覧表示します。ただし、注意してください。操作中です[〜#〜] live [〜#〜]プロセス。)

また、コマンドのpeekfd(Debian Jessieなどのpsmiscパッケージにあります)を使用すると、プロセスのバッファーに何が隠れているかを確認できます。繰り返しますが、/proc/$(pidof python)/fdは、peekfdの引数として有効なファイル記述子を表示します。

Pythonの_-u_を覚えていない場合は、常にコマンドの前に stdbufcoreutils、すでにインストールされている)を付けてstdin /を設定できますstdout/stderrを必要に応じて、バッファーなし、ラインバッファー、またはブロックバッファーに変換します。

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

もちろん、_man pages_はあなたの友達です。おそらくエイリアスもここで役に立つかもしれません。

_alias python='python -u'
_

これで、pythonは、すべてのコマンドラインの作業に常に_-u_を使用します!

19
lornix

まず、Python(または少なくともglibc)のデバッグシンボルがあることを確認してください。オン Fedora1 あなたはそれらをインストールすることができます:

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をフラッシュし、バッファリングも無効にします。 setvbuf 呼び出しの2は、私のシステムの_IONBFの値です。あなたは自分のものを見つける必要があります(grep _IONBF /usr/include/stdio.hがうまくいくはずです)。

CPython 2.7の PyFile_SetBufSizePyFile_WriteString の実装で私が見たことに基づいて、それはかなりうまくいくはずですが、 tいかなる保証も行いません。


1 Fedoraには debuginfo rpms と呼ばれる特別なタイプのRPMが含まれています。これらの自動的に作成されたRPMには、プログラムファイルからのデバッグ情報が含まれていますが、外部ファイルに移動されています。

5

当面の問題に対する解決策はありません。スクリプトが既に開始されている場合、事後バッファリングモードを変更することはできません。これらはすべてメモリ内バッファであり、スクリプトの開始、ファイルハンドルのオープン、パイプの作成などの際に設定されます。

要するに、問題のバッファリングの一部またはすべてが出力のIOレベルで実行されている場合に限り、syncコマンドを実行できますが、これは通常、このような場合には起こりそうにありません。

将来的には、Pythonの-uオプション* スクリプトを実行します。一般に、多くのコマンドには、stdin/stdoutバッファリングを無効にするコマンド固有のオプションがあり、unbufferパッケージのexpectコマンドを使用すると、一般的な成功を収めることもできます。

あ Ctrl+C プログラムが中断されると、システムレベルのバッファがフラッシュされますnlessバッファリングはPython自体によって行われ、独自のバッファをフラッシュするロジックを実装していません)と Ctrl+C。サスペンド、クラッシュ、またはキルはそれほど親切ではありません。

*Stdin、stdout、およびstderrが完全にバッファリングされないようにします。

4
Jason C

Python 2.7.7ドキュメント、セクション「Pythonのセットアップと使用法」、サブセクション 1。コマンドラインと環境 で、これについて説明していますPython argument:

-u

Stdin、stdout、およびstderrが完全にバッファリングされないようにします。重要なシステムでは、stdin、stdout、およびstderrもバイナリモードにしてください。

このオプションの影響を受けないfile.readlines()とファイルオブジェクト(sys.stdinの行)には内部バッファリングがあることに注意してください。これを回避するには、while 1:ループ内でfile.readline()を使用します。

また、この環境変数:

[〜#〜] pythonunbuffered [〜#〜]

これが空でない文字列に設定されている場合、-uオプションを指定することと同じです。

2
harrymc

別の可能な解決策は、コアダンプでプロセスを強制終了し、死後のメモリコンテンツを分析することです。

0
jacek