Зафиксировать выходной буфер вывода в запущенной программе

У меня есть длинный сценарий python, который периодически выводит данные на стандартный вывод, который я вызывал с чем-то вроде:

python script.py > output.txt

Этот скрипт работает некоторое время, и я хочу остановить его с помощью Ctrl + C , но не потерять его. К сожалению, когда я реализовал сценарий, я забыл сбросить буфер после каждой строки вывода с помощью чего-то вроде sys.stdout.flush() ( ранее предложенное решение для принудительной промывки вывода), поэтому ссылаясь Ctrl + C прямо сейчас приведет к потере всего моего вывода.

Если вы задаетесь вопросом, есть ли способ взаимодействовать с запущенным сценарием python (или, в более общем плане, запущенным процессом), чтобы заставить его сбросить свой выходной буфер. Я не спрашиваю, как отредактировать и перезапустить скрипт, чтобы он корректно очистился - этот вопрос связан с взаимодействием с текущим процессом (и, в моем случае, без потери вывода из текущего выполнения кода).

16 голосов | спросил josliber 6 J0000006Europe/Moscow 2014, 17:50:24

6 ответов


2

Кажется, я был слишком осторожен в потере буферизованным выходом после запуска Ctrl-C; в соответствии с этим сообщением . Я должен ожидать, что буфера, который будет сброшен, если моя программа имеет нормальный выход, что было бы, если бы я нажал Ctrl-C. С другой стороны, я потерял бы буферизованный вывод, если бы я убил скрипт с помощью SIGKILL или аналогичного.

ответил josliber 16 J0000006Europe/Moscow 2014, 19:33:30
16

IF , по-настоящему желая этих данных, я предлагаю подключить отладчик gdb к интерпретатору python, на мгновение останавливая задачу, вызывая fsync(1) ( stdout ), отделитесь от него (возобновите процесс) и перейдите к выходному файлу.

Посмотрите /proc/$(pidof python)/fd, чтобы увидеть действительные дескрипторы файлов. $(pidof x) возвращает PID процесса с именем 'x.

# 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 "перечисляет все доступные функции. Будьте осторожны, вы работаете LIVE в процессе.)

Существует также команда peekfd (найдена в psmisc на Debian Jessie и др.), что позволит вам увидеть, что скрывается в буферах процесса. Опять же, /proc/$(pidof python)/fd покажет вам действительные файловые дескрипторы, которые будут представлены в качестве аргументов peekfd.

Если вы не помните -u для python, вы всегда можете префикс команды stdbuf coreutils, уже установлен), чтобы установить stdin /stdout /stderr в буферизированный, буферизированный или буферизированный по желанию:

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

Конечно, man pages - ваши друзья, эй! возможно, псевдоним может быть полезен и здесь.

alias python='python -u'

Теперь ваш python всегда использует -u для всех ваших усилий в командной строке!

ответил lornix 19 J0000006Europe/Moscow 2014, 03:44:02
5

Сначала убедитесь, что у вас есть отладочные символы для Python (или, по крайней мере, glibc). В Fedora 1 вы можете установить их с помощью:

dnf debuginfo-install python

Затем присоедините gdb к исполняемому скрипту и выполните следующие команды:

[[email protected] ~]$ pidof python2
9219
[[email protected] ~]$ 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 должен сделать трюк).

Основываясь на том, что я видел в реализации PyFile_SetBufSize и PyFile_WriteString в CPython 2.7, он должен работать очень хорошо, но Я не могу гарантировать никаких гарантий.


1 Fedora включает специальный тип RPM, называемый debuginfo rpms . Эти автоматически созданные RPM содержат отладочную информацию из файлов программы, но перемещаются во внешний файл.

ответил Cristian Ciupitu 20 J0000006Europe/Moscow 2014, 04:09:11
4

Нет решения вашей непосредственной проблемы. Если ваш скрипт уже запущен, вы не можете изменить режим буферизации после факта. Это все буферы в памяти, и все это настраивается при запуске скрипта, открываются дескрипторы файлов, создаются каналы и т. Д.

Как длинный снимок, если и только если какая-то или вся буферизация, о которой идет речь, выполняется на уровне ввода-вывода на выходе, вы можете сделать sync; но это обычно маловероятно в таком случае.

В будущем вы можете использовать опцию Python -u * для запуска скрипта. В общем, во многих командах есть параметры, специфичные для команды, чтобы отключить буферизацию stdin /stdout, и вы также можете получить общий успех с помощью команды unbuffer из пакета expect.

A Ctrl + C приведет к сбросу буферов системного уровня, когда программа будет прервана , если буферизация выполняется самим Python и он не реализовал логику для сброса собственных буферов с помощью Ctrl + C . Приостановление, сбой или убийство не будут такими добрыми.

* Force stdin, stdout и stderr должны быть полностью не загружены.

ответил Jason C 16 J0000006Europe/Moscow 2014, 19:39:57
2

Python 2.7.7 Документация, раздел «Настройка и использование Python», подраздел 1. Командная строка и среда , описывает этот аргумент Python:

  

-u

     

Force stdin, stdout и stderr должны быть полностью не загружены. О системах   где это имеет значение, также ставьте stdin, stdout и stderr в двоичном режиме.

     

Обратите внимание, что внутри file.readlines () и File есть внутренняя буферизация   Объекты (для строки в sys.stdin), на которые не влияет это   вариант. Чтобы обойти это, вы захотите использовать file.readline ()   через некоторое время 1: цикл.

А также эта переменная среды:

  

PYTHONUNBUFFERED

     

Если для этого параметра задана непустая строка, это эквивалентно заданию   параметр -u.

ответил harrymc 13 J0000006Europe/Moscow 2014, 21:17:27
0

Я думаю, что еще одним возможным решением может быть принудительное уничтожение процесса с выгруженным ядром, а затем анализ посмертно памяти.

ответил jacek 18 ThuEurope/Moscow2014-12-18T20:03:13+03:00Europe/Moscow12bEurope/MoscowThu, 18 Dec 2014 20:03:13 +0300 2014, 20:03:13

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132