可能的重复:
Bash while 循环并从管道读取
我有 Web 编程背景,发现自己对使用本地 shell 的一个特性很感兴趣。据我所知,当程序从文件读取时,它可以以任何必要的速率读取。但我很好奇,当一个程序通过管道获取其他程序的输入并且无法实时处理它时,它是如何工作的?
一个很好的例子是视频编码。假设我将解码器指向视频文件,然后它的输出将作为编码器的输入通过管道传输。解码视频的总大小超过了内存+交换空间,所以我想没有办法完全缓冲它。我发现了对 stdin 和 stdout 的读取和写入调用,但我有兴趣知道当此示例的编码器无法同时处理所有数据时实际会发生什么。它是否以某种方式告知解码器所需的速率?解码器程序是否需要专门针对这样的信号准备并相应地修改其处理速度?如果不是,最后如何平衡?
答案1
当写入器写入管道并且管道已满(其大小限制为几千字节)时,其进程会阻塞,直到其中一个读取器释放一些空间。类似地,当读取器从管道中读取数据时,其进程会阻塞,直到那里有东西为止。
还有异步写入和读取,程序员可以使用它来对这些读取和写入进行排队。
我强烈建议阅读Beej 的指导,从 Beej 开始Unix 进程间通信指南
你用两个参数来调用它,第一个是作者的睡眠时间,第二个是读者的睡眠时间。尝试使用 args0 3
和3 0
#!/bin/sh
write_sleep=$1
read_sleep=$2
writer(){
echo writing output >&2
echo hi
sleep $write_sleep
echo writing output >&2
echo hi
sleep $write_sleep
echo writing output >&2
echo hi
sleep $write_sleep
}
reader(){
while true; do
echo getting input >&2
read input
[ $input ] || { echo input is empty >&2 && break; }
echo $input
sleep $read_sleep
done
}
writer | reader
答案2
管道是编程级别上常见的 UNIX 描述符。当您设置两个程序通过管道进行通信时,它们首先看到的只是它们与之交互的标准输出和标准输入描述符,因为 shell 确实以这种方式设置了它们。当以这种方式设置时,这些描述符有一些特殊性,但是进程与它们交互就像与任何其他文件描述符一样(这是整个 UNIX 哲学,你知道)。
基本上,写入进程可以在管道中写入任意数量的数据,但是,由于管道有最大存储限制(缓冲区),因此如果管道已满,则可能会被阻塞,或者请求可能会被回答为“尝试”如果作者不希望它被阻止,稍后再一次”。
相反,读者可以想读多少就读多少,但如果管道是空的,它也可能被阻塞(或者也用“稍后再试”来回答)。