将文件内容通过管道传递给程序的有效方法
Efficient way to pipe file contents to program
假设我们的命令 cmd
仅通过管道接收输入。给定一个文件名 file.txt
,将其通过管道传输到命令中的最有效方法是什么? (我假设 cat file.txt | cmd
不是很有效..)
让我们用 1 GB 的 blob (dump.data
) 做一个小测试:
使用 >
运算符比从 cat
:
进行管道传输要快得多
$ time cat dump.data | cat >/dev/null
real 0m0.360s
user 0m0.000s
sys 0m0.608s
$ time cat <dump.data >/dev/null
real 0m0.158s
user 0m0.000s
sys 0m0.156s
理论上应该比 <
快一点的唯一方法是 cmd
接受文件名作为其参数并读取文件本身(因为不涉及 IPC - 只有一个进程处理数据)。然而,它在这个测试中没有任何区别:
$ time cat dump.data >/dev/null
real 0m0.158s
user 0m0.000s
sys 0m0.156s
下面是一些其他计时结果
fn="file.txt"
[[ -e $fn ]] && rm "$fn"
for i in {1..100} ; do
echo "Line $i" >> "$fn"
done
arg='{print FNR, [=10=]}'
N=1000
func1() {
for i in $(seq 1 $N) ; do
awk "$arg" "$fn" > "$temp_file"
done
}
func2() {
for i in $(seq 1 $N) ; do
cat "$fn" | awk "$arg" > "$temp_file"
done
}
func3() {
for i in $(seq 1 $N) ; do
while read line ; do
printf "%s\n" "$line"
done <"$fn" | awk "$arg" > "$temp_file"
done
}
func4() {
for i in $(seq 1 $N) ; do
while read line ; do
echo "$line"
done <"$fn" | awk "$arg" > "$temp_file"
done
}
func5() {
for i in $(seq 1 $N) ; do
readarray -t a <"$fn"
printf "%s\n" "${a[@]}" | awk "$arg" > "$temp_file"
done
}
func6() {
for i in $(seq 1 $N) ; do
awk "$arg" > "$temp_file" <"$fn"
done
}
time_it() {
temp_file="tmp_out.txt"
name="func"
{ time "$name"; } |& awk -vfn="$name" 'NR==2 {print fn, substr( , 3, length( ) - 3 ) }'
}
for i in {1..6} ; do
time_it $i
done
我的 Ubuntu 笔记本电脑上单个 运行 的输出是:
func1 1.558
func2 2.273
func3 1.704
func4 1.427
func5 2.188
func6 1.576
请注意,func1
仅用于比较。它不使用管道输入。我们看到对于这个特定的 运行、func4
和 func6
大约和 func1
..
一样快
假设我们的命令 cmd
仅通过管道接收输入。给定一个文件名 file.txt
,将其通过管道传输到命令中的最有效方法是什么? (我假设 cat file.txt | cmd
不是很有效..)
让我们用 1 GB 的 blob (dump.data
) 做一个小测试:
使用 >
运算符比从 cat
:
$ time cat dump.data | cat >/dev/null
real 0m0.360s
user 0m0.000s
sys 0m0.608s
$ time cat <dump.data >/dev/null
real 0m0.158s
user 0m0.000s
sys 0m0.156s
理论上应该比 <
快一点的唯一方法是 cmd
接受文件名作为其参数并读取文件本身(因为不涉及 IPC - 只有一个进程处理数据)。然而,它在这个测试中没有任何区别:
$ time cat dump.data >/dev/null
real 0m0.158s
user 0m0.000s
sys 0m0.156s
下面是一些其他计时结果
fn="file.txt"
[[ -e $fn ]] && rm "$fn"
for i in {1..100} ; do
echo "Line $i" >> "$fn"
done
arg='{print FNR, [=10=]}'
N=1000
func1() {
for i in $(seq 1 $N) ; do
awk "$arg" "$fn" > "$temp_file"
done
}
func2() {
for i in $(seq 1 $N) ; do
cat "$fn" | awk "$arg" > "$temp_file"
done
}
func3() {
for i in $(seq 1 $N) ; do
while read line ; do
printf "%s\n" "$line"
done <"$fn" | awk "$arg" > "$temp_file"
done
}
func4() {
for i in $(seq 1 $N) ; do
while read line ; do
echo "$line"
done <"$fn" | awk "$arg" > "$temp_file"
done
}
func5() {
for i in $(seq 1 $N) ; do
readarray -t a <"$fn"
printf "%s\n" "${a[@]}" | awk "$arg" > "$temp_file"
done
}
func6() {
for i in $(seq 1 $N) ; do
awk "$arg" > "$temp_file" <"$fn"
done
}
time_it() {
temp_file="tmp_out.txt"
name="func"
{ time "$name"; } |& awk -vfn="$name" 'NR==2 {print fn, substr( , 3, length( ) - 3 ) }'
}
for i in {1..6} ; do
time_it $i
done
我的 Ubuntu 笔记本电脑上单个 运行 的输出是:
func1 1.558
func2 2.273
func3 1.704
func4 1.427
func5 2.188
func6 1.576
请注意,func1
仅用于比较。它不使用管道输入。我们看到对于这个特定的 运行、func4
和 func6
大约和 func1
..