管道不需要第一个实例在另一个实例开始之前完成。实际上,实际上它所做的只是将第一个实例的stdout重定向到第二个实例的stdin,因此它们可以同时运行(因为它们必须使分叉炸弹正常工作)。
好吧,确切的输出是:
什么?传递给对方的是:
什么?
':'不会向另一个':'实例写入任何内容,它只是将标准输出重定向到第二个实例的标准输入。如果它在执行过程中写了一些东西(它永远不会做,因为它除了分叉本身什么也不会做),它将转到另一个实例的标准输入。
这有助于将stdin和stdout想象成一堆:
当程序决定从标准输入中读取内容时,写入标准输入的内容都会准备就绪,而标准输出则以相同的方式工作:可以写入的内容,以便其他程序在需要时可以从中读取。
这样一来,就很容易想象出诸如管道之类的情况,其中没有发生通信(两个空堆)或非同步的读写操作。
两次执行的精确度如何?在我看来,:
直到第一个:
完成执行之前,任何内容都不会传递给第二个,实际上这将永远不会结束。
由于我们只是重定向实例的输入和输出,因此不需要第一个实例在第二个实例开始之前完成。实际上通常通常希望两者同时运行,以便第二个可以同时处理第一个正在解析的数据。这就是这里发生的情况,两者都将被调用,而无需等待第一个完成。这适用于所有管道链命令行。
我认为相同的逻辑适用于:(){:|:&} ;:和
:(){ : & };:
做与
:(){ :|: & };:
第一个不起作用,因为即使它以递归方式运行,该函数仍在后台(: &
)中被调用。第一个:
不等到“子” :
返回才结束自身,因此最后您可能只有一个:
运行实例。如果有的:(){ : };:
话,它将起作用,因为第一个:
将等待“子” :
返回,然后将等待其自己的“子” :
返回,依此类推。
就运行多少实例而言,以下是不同的命令:
:(){ : & };:
1个实例(调用:
和退出)-> 1个实例(调用:
和退出)-> 1个实例(调用:
和退出)-> 1个实例-> ...
:(){ :|: &};:
1个实例(调用2 :
并退出)-> 2个实例(每个调用2 :
并退出)-> 4个实例(每个调用2 :
并退出)-> 8个实例-> ...
:(){ : };:
1个实例(调用:
并等待它返回)-> 2个实例(子调用另一个:
并等待它返回)-> 3个实例(子调用另一个:
并等待它返回)-> 4个实例-> ...
:(){ :|: };:
1个实例(调用2 :
并等待它们返回)-> 3个实例(孩子分别调用2 :
并等待它们返回)-> 7个实例(孩子分别调用2 :
并等待它们返回) -> 15个实例-> ...
如您所见,在后台调用函数(使用&
)实际上会减慢fork炸弹的速度,因为被调用方将在被调用函数返回之前退出。
:|:
,第二个:
不需要等待第一个完成。