美是有目共睹的 。Unix之美 , 稍微体会 , 便能得到 。
1969年 , Unix初始 , 没有fork , 没有exec , 没有pipe , 没有 “一切皆文件” , 但是那时它已经是Unix了 。它简单 , 可塑 。
Melvin Conway在1963年的论文中叙述fork思想时就解释说并行路径要用结果来交互 , 也就是在汇合的join点来同步结果 。这个同步点所得到的 , 就是一个并行进程的 输出 。
在此之外 , Unix还有另一个原则 , 就是 组合小程序!
Unix把一系列功能单一的小程序组合成一个复杂的逻辑 , 这个原则有以下优势:
- 每一个小程序都很容易编写 。
- 每一个小程序可以分别完成 。
- 每一个小程序可以分别迭代修复 。
- 多个小程序可以自由组合 。
- …
Unix程序在自身的逻辑之外对外暴露的只有输入和输出 。那么 用输出连接另一个程序输入 就是一种好的方法 。所谓Conway的join点对于Unix进程指的就是输出 。
对外暴露的越少 , 程序越内聚 。这是一种范式 , 类似RISC处理器也是抽象出仅有的load和store来和内存交互 。简单来讲 , Unix程序通过输入和输出来彼此连接 。下面是一幅来自Wiki的图示:
文章插图
详见Pipeline (Unix):
https://en.wikipedia.org/wiki/Pipeline_(Unix)
Unix的另一个原则 , 即著名的 “一切皆文件!” 连接输出和输入的那个管道在Unix中被实现为Pipe , 显然 , 它也是文件 , 一个FIFO文件 。
说实话 , 协作几个小程序形成一个大逻辑的思想还是来自于Convey , 在Convey的论文里 , 他称为 协程 , Pile可以说是直接实现了 Convey协程 之间的交互 。有关这段历史 , 请看:
http://www.softpanorama.org/Scripting/Piporama/history.shtml
用Pipe连接作为输出和输入连接Unix进程可以做成什么事情呢?让我们去感受一个再熟悉不过的实例 , 即数学式子:
文章插图
我们把运算符加号 , 乘号 , 除号(暂不考虑括号 , 稍后解释为什么)这些看作是程序(事实上它们也真的是) , 那么类似数字3 , 5 , 7 , 6就是这些程序的输入了 , 这个式子最终需要一个输出 , 获得这个输出的过程如下:
- 数字3 , 5是加号程序的输入 , 3+5执行 , 它获得输出8.
- 第1步中的输出8连同数字7作为乘号程序的输入 , 8 × 7执行 , 获得输出56.
- 第2步中的输出56连同数字6作为除号的输入 , …
如果你相信数学可以描述整个世界 , 那么Pipe连同Unix程序同样是描述这个世界的语言。
在数学领域 , 程序 就是所有的运算符 , 加号 , 减号 , 乘号 , 除号 , 乘方 , 开方 , 求和 , 积分 , 求导…它们无一例外 , 只做一件事 。
在Unix看来也同样 。它做的事情和下面的应该差不多 , 而且更多:
文章插图
写出上面的式子中每一个数学运算符的程序并不困难 , 比如加号程序:
// plus.c#include <stdio.h>int main(int argc, char **argv){ int a, b; a = atoi(argv[1]); b = atoi(argv[2]); a = a + b; printf("%dn", a);}同样 , 我们可以写出除法 , 直到偏导的程序 。然后我们通过pipe就能将它们组合成任意的数学式子 。
现在谈谈Unix组合程序的具体写法 , 如果我们要化简薛定谔方程 , 我们应该如何用Unix命令写出与上述式子等价的组合程序命令行呢?我们无法像数学家手写那样随意使用括号 , 显然 , 计算机并不认识它 。我们能够使用的只有两个符号:
推荐阅读
- 不需要软件,如何简单实现内外网自由切换?
- 基于windows服务器下的文件备份实现方案
- python使用SocketServer实现网络服务器
- 并使用java实现 一文彻底看懂Base64编码解码原理
- Redis中的发布订阅模式用代码实现就是这么简单
- 使用原生的js实现简易的图片延时加载
- 使用python实现UDP编程
- Go语言实现LeetCode算法:958 检查二叉树的完整性
- PHP实现站内信
- SSH工作过程