命令替换和进程替换的区别

17

我正在尝试理解这两个类似命令之间的差异。

aa=$(foo | bar | head -1)
read aa < <(foo | bar | head -1)
  • 我知道<()需要#!/bin/bash,但这会使它变慢吗?
  • 它们创建相同数量的子shell吗?
  • 它们需要相同数量的bashsh进程吗?

我想使用性能最佳的命令。

4个回答

8
  1. 非POSIX模式下,Bash更快。
  2. 这取决于具体的实现和平台细节。
    • 在Bash中,两者都需要相同数量的进程。如果未启用lastpipe,则每个管道元素都需要一个进程,加上一个替换的子shell和父进程。
    • 在Bash中,如果启用了lastpipe,管道的最后一个元素将在两种情况下执行exec而不进行分叉,仍然需要相同数量的进程。
    • 在ksh93中,在这种情况下,两者都应该需要相同数量的进程,但是如果最后的管道元素是内置的,则会在命令替换的父进程中运行,使其更快。
    • 在Bash和ksh93中,如果在不支持/dev/fd/*的系统上编译了shell,则shell将为进程替换创建命名管道。这可能会影响性能。
  3. 前面的项目可能应该放在这里。请注意,“子shell”并不一定意味着单独的进程,尽管在几乎所有shell中都是这样(除了除Bash以外的所有支持它的shell中的$(<...))。在mksh和ksh93中,还有${ ;}风格的命令替换,但每个shell实现都不同。在ksh93中,它可能会提高速度,也可能不会。在mksh中,可能不会。mksh不支持进程替换,zsh不支持(也没有模拟的方法)BASHPID,因此我没有研究过。

在Bash中,命令替换与进程替换本质上并没有更快的一方,但在read的情况下,head是多余的,因为您只需要读取一行。顺便说一句,总是使用head -n ...---1不具备可移植性。除非您希望shell篡改输入,否则不要使用没有-rread


3
改善性能的最佳方法是尽可能减少forks和pipes的使用。
就像所述的那样,您不应该担心性能问题。99%的执行时间很可能由特定命令决定,而不是进程替换与命令替换之间的差异。您知道优化的第一法则吗?不要去优化。特别是如果您正在牺牲可移植性。使用 $(whatever) 并忘记其他所有内容。如果您真的担心性能,则需要解决命令/管道/分叉。否则,您就像试图通过从眼睛中挤出眼泪来减轻体重。

2

1
哎呀,按照陈述的方式,这不太正确。希望你不介意我稍微调整了一下它。在这两种情况中都涉及到“文件描述符”,并且两者都会产生子shell,至少在Bash中也总是暗示至少一个fork。在我的更广泛的测试中,“read -r x < <(... )”和“x=$(...)”之间的差异几乎无法测量,无论是迭代小输入还是单个大输入,分配速度略快(如预期),但在原始问题中,这两个解决方案都是奇怪和次优的。 - ormaaj

1

进程替换可以绕过由管道/命令替换创建的子shell。替换语法被FIFO或FD的名称所取代,并且其中的命令在后台运行。替换与参数扩展和命令替换同时进行。

请查看有关使用“tee”进行进程替换的信息。

http://mywiki.wooledge.org/ProcessSubstitution


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接