我有一个awk脚本向stdout发送长字符串(> 10K字符)。
我想增加缓冲区大小,以便一次写入那些长字符串的较大块。我已经将两个管道的时间设置为不同的-o尺寸,但是没有显着的变化
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%)。
我的问题是我是否正确使用stdbuf?谢谢。
FZ。
答案 0 :(得分:1)
stdbuf
所做的是改变C stdlib中的缓冲,即stdin
,stdout
或stderr
FILE*
的缓冲区。
它不会更改内核中管道缓冲区的大小。这可能是您没有看到任何变化的原因。
众所周知的问题是管道缓冲区大小无法更改且非常小。处理大型文件时,通常最好将中间结果写入文件,而不是将它们传输到另一个应用程序中。因为管道缓冲区非常小,所以在通过管道进行通信的应用程序之间会有很多上下文切换,其开销可能会使应用程序运行时相形见绌。
答案 1 :(得分:0)
stdbuf
命令设法改变执行命令的标准I / O通道的缓冲。但是,它(我认为它不能)改变O / S中管道的容量。所以,我不希望看到性能有任何差异。
请注意,不同之处在于,对于大缓冲区,awk
将最终在一个怪异的write()
系统调用中发送所有数据(除非infile.txt
,由脚本修改,它本身大于100 MiB),而通常它会在填充0.5到8 KiB之间的某个缓冲区时写入。然而,如此巨大的write()
的好处是微乎其微的;它仍然必须被O / S分割以适应管道(除非O / S做不同的事情 - 经典,我所描述的将是真的。)
答案 2 :(得分:0)
缓冲在管道中的另一种方法是使用dd
命令。我发现在某些情况下stdbuf
不起作用(例如:在OSX上为git
),在继续进行下一步之前,先排空输出是很有用的。这是一个示例,该示例将在向sort
发送任何内容之前先消耗1 MB的空间,同时还要写入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