![]() |
|
Модераторы: korob2001, ginnie |
![]()
|
|
| CaptainFlint |
|
||||
|
Искатель сокровищ ![]() ![]() Профиль Группа: Участник Сообщений: 393 Регистрация: 26.2.2003 Где: Москва Репутация: нет Всего: 23 |
Система - Linux.
Перл-скрипт изнутри себя запускает приложение, исходники которого мне недоступны. Это приложение пишет и в stdout, и в stderr. Задача такова: перехватить эти два потока и выводить их в файл построчно, отмечая в начале каждой строки, из которого потока она пришла. Например:
При этом главное - сохранить порядок строк таким же, каким он был бы при стандартном выводе обоих потоков в терминал. Первую-то проблему я решил (через два именованных пайпа), но, к сожалению, если строки выводятся в stdout и stderr слишком часто, их порядок в выходном файле может нарушиться (из двух процессов, висящих на чтении пайпов, первым получает управление случайно выбранный, а не тот, на чей пайп раньше пришли данные). Вопрос: можно ли как-то решить эту задачу? Я понимаю, что в общем случае, для сложных систем полная синхронизация невозможна, но если программа пишет:
то в выходном файле они ни в коем случае не должны оказываться в обратном порядке! В терминал-то выводится всё правильно... -------------------- Почему же, ё-моё, ты нигде не пишешь "ё"? -------------------- Для тех, кто не знает: CaptainFlint - это бывший Константин. ;) |
||||
|
|||||
| Nab |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 582 Регистрация: 25.3.2006 Где: Kiev Репутация: 26 Всего: 37 |
Я тут вижу два варианта.
Первый, это сразу сделать 2>&1 , но тут трабла, что выходной поток вам самим прийдется анализировать, и определять какое сообщение какому потоку соответствует, потому как вам они будут валиться в один поток. Второй, это временные метки, вам самому возможно прийдется буферизировать и сортировать на выходе. Задача не очень простая PS: Есть еще один вариант Только обсуждали в соседнем топике Как гарантировано закрыть файл Возможно поможет... -------------------- Чтобы правильно задать вопрос нужно знать больше половины ответа... Perl Community FREESCO in Ukraine |
|||
|
||||
| DiverD |
|
|||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 225 Регистрация: 14.9.2005 Где: Белорусь Репутация: 1 Всего: 2 |
если я тебя правильно понял , томожет тебе нужна воспользоваться
--------------------
[ FreeBSD & pERL p0WER eVERY dAY ] |
|||
|
||||
| CaptainFlint |
|
||||||
|
Искатель сокровищ ![]() ![]() Профиль Группа: Участник Сообщений: 393 Регистрация: 26.2.2003 Где: Москва Репутация: нет Всего: 23 |
Вот-вот, это никак не подходит, потому как никаких сигнальных строк там не содержится. Т.е. выцепить из объединённого потока нужные строки невозможно.
Я бы рад, но именно это и не получается сделать. Какой из процессов-слушателей раньше получит управление, тот и впихнёт более раннюю временную метку, так что толку от этого...
Уже давно отключил (через $| ), всё равно смешиваются.
Пользуюсь. От более раннего вызова это не спасает. Возможно, конечно, я ошибаюсь, т.к. никогда глубоко в этом не копался, но, как мне кажется, проблема в следующем: Есть два процесса, один слушает пайп, прицепленный к stdout'у пишущего приложения, второй слушает пайп, прицепленный к stderr'у. Большую часть времени оба они висят, заблокированные в функции read, пока приложение чего-нибудь не запишет. И вот, приложение в течение одного кванта времени успевает записать и в OUT, и в ERR. Наступает следующий квант (или просто по сигналу срабатывает планировщик), видит, что есть два висящих процесса, оба готовы к разблокировке. И по каким-то своим алгоритмам один из этих процессов разблокирует. И этим процессом вовсе не обязательно оказывается тот, в который данные были послалы раньше. В этом случае хоть flock, хоть что другое, уже не поможет. Надо каким-то образом умудриться заставить сработать нужный процесс сразу же, как только данные появились в пайпе. Но вот как это сделать... -------------------- Почему же, ё-моё, ты нигде не пишешь "ё"? -------------------- Для тех, кто не знает: CaptainFlint - это бывший Константин. ;) |
||||||
|
|||||||
| CaptainFlint |
|
|||
|
Искатель сокровищ ![]() ![]() Профиль Группа: Участник Сообщений: 393 Регистрация: 26.2.2003 Где: Москва Репутация: нет Всего: 23 |
Нарыл сейчас функцию open3 (модуль IPC::Open3), но с ней в точности та же проблема. Просто оказываются готовыми к чтению сразу два хэндла, и который из них пришёл раньше - фиг определишь.
PS: Упс... А почему сообщения не склеились?.. Это сообщение отредактировал(а) CaptainFlint - 7.12.2006, 13:53 -------------------- Почему же, ё-моё, ты нигде не пишешь "ё"? -------------------- Для тех, кто не знает: CaptainFlint - это бывший Константин. ;) |
|||
|
||||
| Nab |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 582 Регистрация: 25.3.2006 Где: Kiev Репутация: 26 Всего: 37 |
ну тады пробуй так:
сделай ему tee в третий поток, и слушай три сразу, стандартный, ошибок, и общий, по которому и будешь определять порядок -------------------- Чтобы правильно задать вопрос нужно знать больше половины ответа... Perl Community FREESCO in Ukraine |
|||
|
||||
| CaptainFlint |
|
|||
|
Искатель сокровищ ![]() ![]() Профиль Группа: Участник Сообщений: 393 Регистрация: 26.2.2003 Где: Москва Репутация: нет Всего: 23 |
Не подскажешь командную строку, как такое сотворить? Я уже думал над таким вариантом, но что-то не получается... -------------------- Почему же, ё-моё, ты нигде не пишешь "ё"? -------------------- Для тех, кто не знает: CaptainFlint - это бывший Константин. ;) |
|||
|
||||
| Nab |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 582 Регистрация: 25.3.2006 Где: Kiev Репутация: 26 Всего: 37 |
Ну вот есть команда tee, но как правильно ее записать фиг ее знает
http://www.opennet.ru/docs/RUS/shutil/shellutils_6.html http://www.opennet.ru/man.shtml?topic=tee&...1&russian=0 по идее вместо файла можно указать пайп спецом перед эти созданный, и читать с него.... -------------------- Чтобы правильно задать вопрос нужно знать больше половины ответа... Perl Community FREESCO in Ukraine |
|||
|
||||
| CaptainFlint |
|
|||
|
Искатель сокровищ ![]() ![]() Профиль Группа: Участник Сообщений: 393 Регистрация: 26.2.2003 Где: Москва Репутация: нет Всего: 23 |
Nab
М-да... Маны-то я и до этого читал... Похоже, толку здесь от tee не будет. Если я stdout и stderr с его помощью куда-то перенаправлю (хоть в один файл, хоть в два, хоть в три), они всё равно будут обрабатываться двумя разными процессами (как минимум), и эти два процесса уже будут получать данные вразнобой. С ума сойти, неужели такая элементарная задача не имеет решения? -------------------- Почему же, ё-моё, ты нигде не пишешь "ё"? -------------------- Для тех, кто не знает: CaptainFlint - это бывший Константин. ;) |
|||
|
||||
| Nab |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 582 Регистрация: 25.3.2006 Где: Kiev Репутация: 26 Всего: 37 |
Покаж код плиз, которым читаешь из потоков, здается мне, мы не там ищем...
-------------------- Чтобы правильно задать вопрос нужно знать больше половины ответа... Perl Community FREESCO in Ukraine |
|||
|
||||
| CaptainFlint |
|
||||||||||
|
Искатель сокровищ ![]() ![]() Профиль Группа: Участник Сообщений: 393 Регистрация: 26.2.2003 Где: Москва Репутация: нет Всего: 23 |
writer.pl:
reader.pl:
Очищаю файл /tmp/result, затем в одном терминале запускаю:
Во втором:
В третьем:
После окончания работы writer'а смотрю результат в /tmp/result. Строки, начинающиеся с "o:" пришли из stdout'а, с "e:" - из stderr'а. -------------------- Почему же, ё-моё, ты нигде не пишешь "ё"? -------------------- Для тех, кто не знает: CaptainFlint - это бывший Константин. ;) |
||||||||||
|
|||||||||||
| Nab |
|
||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 582 Регистрация: 25.3.2006 Где: Kiev Репутация: 26 Всего: 37 |
Упс, какой ужас....
Я нашел один рецепт в CookBook, как это сделать...
То есть мы его помечаем до слияния с выводом ошибок... во writer.pl я убрал только создание пайпов, а reader.pl таков:
чтобы не извращаться с внешней командой, то совет от туда же: perldoc IPC::Open2 или IPC::Open3. Туту вообще все внутри одного скрипта делаеться... и страшные внешние команды писать вообще не надоть... Добавлено @ 23:52 Нееее, мой вариант, тоже выдает сначала STDERR а потом обычный вывод -------------------- Чтобы правильно задать вопрос нужно знать больше половины ответа... Perl Community FREESCO in Ukraine |
||||
|
|||||
| Nab |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 582 Регистрация: 25.3.2006 Где: Kiev Репутация: 26 Всего: 37 |
Вот таки передрал рецепт из CookBook:
writer.pl остается таким, а readerюзд таков:
Все пашет замечательно, и порядок вполне сохраняется... -------------------- Чтобы правильно задать вопрос нужно знать больше половины ответа... Perl Community FREESCO in Ukraine |
|||
|
||||
| Danissimo |
|
|||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 150 Регистрация: 14.8.2006 Где: Санкт-Петербург Репутация: 1 Всего: 1 |
Я про фундаментальную невозможность решить эту задачу в том виде, в котором она поставлена в полном объеме. Представьте себе, что у вас 2 независимых процессора. На кождом из них крутиться поток (thread). Пусть первый поток в момент времени t написал в stdout строку. Пусть в то же самое время второй поток написал в stderr. Я утверждаю, что смысл условия "сохранение порядка" не определен, так как события произошли одновременно.
Этим я всего лишь хотел проиллюстрировать фундаментальный принцип многопоточной обработки данных, когда вы не в состоянии сказать, какое событие произошло раньше, если не прибегаете к блокировкам в том или ином виде. Посмотрите формализм Лампорта. Так как код закрыт, то вы не знаете, сколько потоков выолняют запись в stdout и stderr, следовательно (не) перепутать строки не возможно в принципе. Или знаете, что только один поток пишет в потоки вывода? Вот такие мысли. Добавлено @ 11:47 Ещещ мысль. А что если размеры буферов у потоков stderr и stdout разные? А что если для одного потока автофлаш включен, а длдя другого нет. В этом случае даже для одного потока строки на выходе уже будут перепутанными. |
|||
|
||||
| Nab |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 582 Регистрация: 25.3.2006 Где: Kiev Репутация: 26 Всего: 37 |
Теория эт конечно хорошо, но то что Вы, Danissimo, описываете, как правило относиться к постоянному выводу нескольких равноправных потоков. Вывод в STDERR происходит при ошибке одного из потоков, и соответственно порядок возникновения события ошибки вполне определен. Не думаю что бы кто-то в здравом уме, передавал состояние ошибки в другой поток для вывода, при этом сам продолжая выводить данные...
Даже если и используется отдельный поток или процесс, для контроля за состоянием другого процесса, то он контролирует подозреваю все состояния а не только ошибочные, и соответственно может при их получении синхронизировать с основным показателями состояния потока. Что в принципе и пытались мы реализовать в этом топике... -------------------- Чтобы правильно задать вопрос нужно знать больше половины ответа... Perl Community FREESCO in Ukraine |
|||
|
||||
![]()
|
| Правила форума "Perl" | |
|
|
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, korob2001, sharq. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Perl: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |