2014-02-10 4 views
3

У меня проблемы с Perl в Windows (как ActivePerl, так и Strawberry), при перенаправлении скрипта STDOUT на канал и использовании функции sleep(). Попробуйте следующее:Перл STDOUT перенаправлен на канал, нет выхода после вызова sleep()

perl -e "for (;;) { print 'Printing line ', $i++, \"\n\"; sleep(1); }" 

Это работает как ожидалось. Теперь труба его тройник (или какой-то файл, такой же результат):

perl -e "for (;;) { print 'Printing line ', $i++, \"\n\"; sleep(1); }" | tee 

Там нет никакого вывода вообще, тройник не захватывает ничего. Тем не менее, perl-скрипт все еще запущен, только ничего нет в STDOUT, пока скрипт не завершится, а затем весь вывод будет сбрасываться в tee. Кроме того, если буфер STDOUT заполняет сценарий, он может зависать.

Теперь, если вы удалите сон (звонок), труба работает, как ожидалось! Что происходит?

Я нашел обходное решение; отключение буферизации STDOUT с помощью $ | = 1 заставляет трубу работать при использовании сна, но ... почему? Может ли кто-нибудь объяснить и предложить лучшее решение?

+0

Где ваша программа 'tee'? и что вы подразумеваете под «может повесить»? ты его повесил? – ysth

+0

Я попробовал два разных бинарных файла GNU tee, и даже третий из них был разработан на C# в том же поведении. Кроме того, просто перенаправление на файл с «>» дает такое же поведение. Без сна все в порядке, после этого нет выхода до завершения скрипта. И да, у нас есть сценарии, которые работают весь день, и мы возвращаемся, чтобы найти их подвешенными. – Zybex

+0

Единственное, что изменяет 'sleep', заключается в том, что ваш скрипт не заканчивается немедленно и, следовательно, его буфер сброшен. Это не имеет никакого отношения к «ти». Тем не менее, я также испытал, что приложения с постоянным выходом страдают от буферизации. В нашем случае ОС продолжала буферизацию так долго, ожидая уменьшения объема вывода, что, когда он, наконец, должен был скрыться и «синхронизироваться», он часто занимает слишком много времени, и буфер переполняется, потому что выход остается высоким. Мы вынудили синхронизацию каждые 4 минуты, чтобы исправить это. '$ | = 1' может не исправить это, вам, возможно, придется называть' sync' периодически. – DeVadder

ответ

4

Вы страдаете от буферизации. Добавьте $| = 1; в бункер STDOUT.

Все дескрипторы файлов, кроме STDERR, буферизуются по умолчанию, но STDOUT использует минимальную форму буферизации (сбрасывается символами новой строки) при подключении к терминалу. Подставляя терминал для трубы, нормальная буферизация восстанавливается.

Удаление вызова sleep не изменяет ничего, кроме как ускоряет работу. Вместо того, чтобы набирать минуты для заполнения буфера, требуется миллисекунды. С или без него вывод по-прежнему записывается в блоки 4k или 8k (в зависимости от вашей версии Perl).

+0

Я действительно сказал, что нашел этот конкретный «вопрос» в моем вопросе выше. Это все еще не объясняет, почему добавление вызова сна заставляет его вести себя по-другому. – Zybex

+1

Это не добавление вызова сна, это добавление '| tee', и я объяснил, почему это имеет значение. «Сон» не является фактором здесь; то же самое происходит с или без него. Это происходит гораздо быстрее, не спать. – ikegami

+0

Это не тройник, и хотя это точно связано с буферизацией, это не вся история.Сон определенно меняет поведение, и я хотел бы знать, почему. Если вы используете perl sleep(), вывод полностью прекращается (попробуйте написать 100 строк, а не один). Если вы замените sleep для эквивалентного select (undef, undef, undef, 1), он отлично работает. Если вы замените его на «sleep 1» (backticks), он также отлично работает. Пожалуйста, попробуйте. .. – Zybex

 Смежные вопросы

  • Нет связанных вопросов^_^