Обработка трубы - PullRequest
       21

Обработка трубы

29 голосов
/ 21 августа 2008

Кто-нибудь знает, как bash обрабатывает отправку данных по каналам?

cat file.txt | tail -20

Эта команда печатает все содержимое файла file.txt в буфер, который затем читается хвостом? Или эта команда, скажем, печатает содержимое файла file.txt построчно, а затем делает паузу в каждой строке для обработки хвоста, а затем запрашивает дополнительные данные?

Причина, по которой я спрашиваю, состоит в том, что я пишу программу на встроенном устройстве, которое в основном выполняет последовательность операций с некоторым фрагментом данных, где выходные данные одной операции отправляются как входные данные следующей операции. Я хотел бы знать, как linux (bash) справляется с этим, поэтому, пожалуйста, дайте мне общий ответ, а не конкретно, что происходит, когда я запускаю "cat file.txt | tail -20".

Заранее благодарю за ответы!

РЕДАКТИРОВАТЬ: Shog9 указал на соответствующую статью в Википедии, это не привело меня непосредственно к статье, но помогло мне найти это: http://en.wikipedia.org/wiki/Pipeline_%28Unix%29#Implementation, в котором действительно была информация, которую я искал.


Прошу прощения, что не прояснил себя. Конечно, вы используете канал и, конечно, вы используете stdin и stdout соответствующих частей команды. Я предположил, что это было слишком очевидно, чтобы утверждать.

Я спрашиваю, как это обрабатывается / реализуется. Поскольку обе программы не могут работать одновременно, как данные передаются со стандартного ввода в стандартный вывод? Что произойдет, если первая программа генерирует данные значительно быстрее, чем вторая программа? Выполняет ли система первую команду до тех пор, пока она либо не будет прервана, либо ее буфер stdout не заполнится, а затем перейдет к следующей программе и т. Д. В цикле, пока не останется больше данных для обработки или пока не появится более сложный механизм

Ответы [ 3 ]

54 голосов
/ 21 августа 2008

Я решил написать чуть более подробное объяснение.

«Волшебство» здесь заключается в операционной системе. Обе программы запускаются примерно в одно и то же время и работают в одно и то же время (операционная система назначает им интервалы времени для запуска процессора), как и любой другой одновременно запущенный процесс на вашем компьютере (включая терминальное приложение и ядро). , Таким образом, перед передачей любых данных процессы выполняют любую необходимую инициализацию. В вашем примере tail анализирует аргумент '-20', а cat анализирует аргумент 'file.txt' и открывает файл. В какой-то момент хвост достигает точки, где ему требуется ввод, и он сообщает операционной системе, что ожидает ввода. В какой-то другой момент (до или после, это не имеет значения) cat начнет передавать данные в операционную систему, используя стандартный вывод. Это входит в буфер в операционной системе. В следующий раз, когда tail получает временной интервал на процессоре после того, как некоторые данные были помещены в буфер cat, он извлечет некоторое количество этих данных (или всех их), которые покидают буфер в операционной системе. Когда буфер пуст, в какой-то момент tail придется ждать, пока cat выдаст больше данных. Если cat выводит данные намного быстрее, чем tail обрабатывает их, буфер расширяется. В конечном итоге cat завершит вывод данных, но tail все равно будет обрабатывать, поэтому cat закроется, а tail обработает все оставшиеся данные в буфере. Операционная система будет сигнализировать хвост, когда их больше нет входящих данных с EOF. Хвост обработает оставшиеся данные. В этом случае tail, вероятно, просто получает все данные в циклический буфер из 20 строк, и когда операционная система сообщает, что больше нет входящих данных, он затем выгружает последние двадцать строк в свой собственный стандартный вывод, который просто отображается в терминале. Поскольку tail - намного более простая программа, чем cat, она, скорее всего, будет проводить большую часть времени в ожидании, когда cat поместит данные в буфер.

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

Чтобы получить немного больше подробностей, если вы откроете какой-нибудь монитор процессов (специфичный для операционной системы), например 'top' в Linux, вы увидите полный список запущенных процессов, большинство из которых эффективно используют 0% от процессор. Большинство приложений, если они не обрабатывают данные, проводят большую часть своего времени, ничего не делая. Это хорошо, потому что позволяет другим процессам иметь беспрепятственный доступ к процессору в соответствии с их потребностями. Это достигается в основном тремя способами. Процесс может перейти к инструкции режима сна (n), где он в основном говорит ядру подождать n миллисекунд, прежде чем дать ему еще один временной интервал для работы. Чаще всего программе нужно ждать чего-то от другой программы, например, «хвоста», ожидающего поступления большего количества данных в буфер. В этом случае операционная система активизирует процесс, когда будет доступно больше данных. Наконец, ядро ​​может выгрузить процесс в середине выполнения, предоставляя некоторые процессорные интервалы другим процессам. 'cat' и 'tail' - простые программы. В этом примере tail тратит большую часть своего времени в ожидании большего количества данных в буфере, а cat тратит большую часть своего времени в ожидании, пока операционная система извлекает данные из жесткого диска. Узким местом является скорость (или медлительность) физического носителя, на котором хранится файл. Эта ощутимая задержка, которую вы можете обнаружить при первом запуске этой команды, - это время, которое требуется считывающим головкам на дисководе для поиска позиции на жестком диске, где находится file.txt. Если вы запустите команду во второй раз, операционная система, скорее всего, сохранит содержимое файла file.txt в кэше, и вы вряд ли увидите заметную задержку (если только файл file.txt не очень большой или файл больше не кэшируется). .)

Большинство операций, выполняемых на вашем компьютере, связаны с вводом-выводом, то есть обычно вы ожидаете получения данных с жесткого диска, сетевого устройства и т. Д.

1 голос
/ 21 августа 2008

Shog9 уже ссылался на статью в Википедии, но в разделе реализации есть нужные детали. Базовая реализация представляет собой ограниченный буфер.

0 голосов
/ 21 августа 2008

cat просто распечатает данные на стандартный вывод, который будет перенаправлен на стандартный ввод хвоста. Это можно увидеть на странице руководства bash.

Другими словами, паузы не происходит, tail просто читает стандартное сообщение, а cat просто пишет стандартное сообщение.

...