Brian Kernighan 在此视频中解释了早期贝尔实验室对基于内存限制的小型语言/程序的吸引力
一台大机器将是 64 k 字节——K,而不是 M 或 G——这意味着任何单独的程序都不会很大,所以有一种自然的趋势,即编写小程序,然后是管道机制,基本上是输入输出重定向,可以将一个程序链接到另一个程序。
但考虑到数据必须存储在 RAM 中才能在程序之间传输,我不明白这如何限制内存使用。
来自维基百科:
在大多数类 Unix 系统中,一个管道的所有进程同时启动[强调我的],它们的流适当连接,并由调度程序与机器上运行的所有其他进程一起管理。将 Unix 管道与其他管道实现区分开来的一个重要方面是缓冲的概念:例如,发送程序每秒可能产生 5000 个字节,而接收程序每秒只能接受 100 个字节,但不能数据丢失。相反,发送程序的输出保存在缓冲区中。当接收程序准备好读取数据时,管道中的下一个程序从缓冲区读取。在 Linux 中,缓冲区的大小为 65536 字节 (64KB)。如果需要,可以使用名为 bfr 的开源第三方过滤器来提供更大的缓冲区。
这让我更加困惑,因为这完全违背了小程序的目的(尽管它们在一定程度上是模块化的)。
我唯一能想到的解决我的第一个问题(内存限制有问题取决于大小数据)的唯一方法是,当时根本没有计算大型数据集,而真正的问题管道是要解决的程序本身所需的内存量。但是鉴于维基百科引用中的粗体文本,即使这让我感到困惑:因为一次没有实施一个程序。
如果使用临时文件,所有这些都会很有意义,但我的理解是管道不会写入磁盘(除非使用交换)。
例子:
sed 'simplesubstitution' file | sort | uniq > file2
Run Code Online (Sandbox Code Playgroud)
我很清楚这sed是读取文件并逐行吐出。但是sort,正如 BK 在链接的视频中所说的那样,是一个句号,所以所有的数据都必须被读入内存(或者是吗?),然后它被传递给uniq,这(在我看来)将是一个-一行一次的程序。但是在第一个和第二个管道之间,所有数据都必须在内存中,不是吗?
Ste*_*itt 49
数据不需要存储在 RAM 中。如果读者不在或跟不上,管道会阻塞他们的作者;在 Linux(和大多数其他实现,我想)下有一些缓冲,但这不是必需的。正如mtraceur和JdeBP所提到的(见后者的答案),早期版本的 Unix 缓冲管道到磁盘,这就是它们如何帮助限制内存使用:处理管道可以拆分为小程序,每个程序都会在磁盘缓冲区的限制内处理一些数据。小程序占用更少的内存,管道的使用意味着处理可以序列化:第一个程序将运行,填充其输出缓冲区,暂停,然后第二个程序将被调度,处理缓冲区等。现代系统是命令比早期的 Unix 系统大得多,并且可以并行运行许多管道;但是对于大量数据,您仍然会看到类似的效果(并且这种技术的变体用于“大数据”处理)。
在你的例子中,
sed 'simplesubstitution' file | sort | uniq > file2
Run Code Online (Sandbox Code Playgroud)
sedfile根据需要从中读取数据,然后在sort准备好读取时写入;如果sort未准备好,则写入块。数据确实最终确实存在于内存中,但这是特定于 的sort,并sort准备处理任何问题(如果要排序的数据量太大,它将使用临时文件)。
您可以通过运行查看阻塞行为
strace seq 1000000 -1 1 | (sleep 120; sort -n)
Run Code Online (Sandbox Code Playgroud)
这会产生相当数量的数据并将其传送到一个在前两分钟内还没有准备好读取任何内容的进程。您将看到许多write操作通过,但很快seq就会停止并等待两分钟过去,被内核阻止(write系统调用等待)。
Jde*_*eBP 35
但考虑到数据必须存储在 RAM 中才能在程序之间传输,我不明白这如何限制内存使用。
这是你的根本错误。早期版本的 Unix 没有在 RAM 中保存管道数据。他们将它们存储在光盘上。管道有 i 节点;在被表示为管道设备的圆盘设备上。系统管理员运行了一个程序/etc/config来指定(除其他外)哪个磁盘上的哪个卷是管道设备,哪个卷是根设备,哪个是转储设备。
待处理数据的数量受到以下事实的限制:只有磁盘上 i-node的直接块用于存储。这种机制使代码更简单,因为从管道读取的算法与读取常规文件所采用的算法大致相同,但由于管道不可查找且缓冲区是循环的,因此进行了一些调整。
这种机制在 1980 年代中后期被其他机制所取代。SCO XENIX 获得了“高性能管道系统”,它用内核缓冲区取代了 i 节点。4BSD 将未命名的管道制作成 socketpairs。AT&T 使用 STREAMS 机制重新实现了管道。
当然,sort程序执行了有限的 32KiB 输入块的内部排序(或者如果 32KiB 不可用,它可以分配任何更小的内存量),将排序结果写入中间stmX??文件,/usr/tmp/然后在其中外部合并排序以提供最终结果输出。
config(1M)”。 Unix 程序员手册: 3. 系统管理工具。霍尔特、莱因哈特和温斯顿。ISBN 0030093139。第 23-28 页。