我有一个awk脚本发送长字符串(>10K字符)到stdout。
我想增加缓冲区大小,以便一次写入更大的长字符串块。我在下面用不同的- 0大小计时两个管道,但没有明显的变化
time stdbuf -o 100MB awk -f processing.awk infile.txt | sort -k1,1 > outfile.txt
time stdbuf -o 100MB awk -f processing.awk infile.txt > outfile.txt
real/user/sys计时都非常相似(每个指标+- 10%)。
我的问题是我是否使用stdbut正确的方式?谢谢你。
FZ .
stdbuf
所做的是改变C标准库中的缓冲区,即stdin
, stdout
或stderr
FILE*
的缓冲区。
它不会改变内核中管道缓冲区的大小。这可能就是你看不到任何变化的原因。
众所周知,管道缓冲区的大小是不可改变的,并且非常小。在处理大文件时,通常最好将中间结果写入文件,而不是将它们管道到另一个应用程序中。由于管道缓冲区非常小,因此将在通过管道通信的应用程序之间进行大量上下文切换,其开销可能会使应用程序运行时相形见绌。
stdbuf
命令管理更改所执行命令的标准I/O通道的缓冲。但是,它不会(我不认为它可以)改变O/S中管道的容量。所以,我不希望在性能上看到任何差异。
请注意,不同之处在于,使用大缓冲区时,awk
最终将在单个巨大的write()
系统调用中发送所有数据(除非infile.txt
,由脚本修改,本身大于100 MiB),而通常它会在填充0.5到8 KiB之间的缓冲区时写入。然而,如此巨大的write()
的好处是微乎其微的;它仍然必须由O/S分割以适应管道(除非O/S做不同的事情-通常,我所描述的是正确的)。
在管道中进行缓冲的另一种方法是使用dd
命令。我发现了一些stdbuf
不工作的情况(例如:OSX上的git
),在进行管道的下一步之前将输出排干是有用的。下面是一个示例,在向sort
发送任何内容之前将消耗1MB,同时还写入1MB块:
awk -f processing.awk infile.txt |
dd bs=1000000 | # drain/write 1 MB chunks
sort -k1,1 > outfile.txt
另一个有趣的用例:
git ls-remote origin |
# obviously psuedo-awk, might print out :refs/tags/{old_versions}
awk '/filter for interesting stuff/ {massage output}' |
dd bs=1000000 2> /dev/null | # drain 1 MB and suppress block summary
xargs -n 10 git push origin