别逐行刷新了:nullprogram 提出“空闲即刷新”的输出缓冲
作者:林序
nullprogram 11月5日发文,主张终端输出不必每遇换行就刷新,改成缓冲区空闲约百毫秒后整块写出;Hacker News 讨论中有人质疑延时取值、截止时间重置与管道写入原子性,原文没给基准测试。
11月5日,技术博客 nullprogram 发文主张:终端程序不必每遇到换行符就刷新输出,可以改成“缓冲区空闲一小会儿再整块写出”,既能及时显示,又能接近全缓冲的速度 。
行缓冲的问题,常用命令行的人基本都遇过。程序直接连接终端时,C 库默认一遇到换行符就把缓冲内容交给系统,导致写入过于零碎:原文用 strace 观察,glibc 甚至会把一个字符串中的换行符拆成两次写入。比如 unzip 每解压一个文件就打印文件名,打印本身就能拖慢解压,作者宁可关掉输出、加上 -q 参数重跑 。可输出一旦接入管道或重定向到文件,库又自动换成全缓冲,攒满才写:日志迟迟不出现,进程被杀时,尚未写出的尾段也会一起丢失 。
替代做法是给缓冲区加一个截止时间,比如约100毫秒,在干活间隙顺手检查,超时就整块写出,不用另开线程。这段时间里处理完的几个文件名会一起输出,界面不变,速度更快 。
讨论中也有人补充和提出异议。这则链接在 Hacker News 上有 112 分 :有人觉得100毫秒太长,1至10毫秒更合适;有人指出按原文写法,截止时间可能被反复推后;有人提醒多个进程写同一条管道时,合并后的单次写入要小于 PIPE_BUF(管道保证写入不互相穿插的最小单位),否则输出会交错;也有人补充 setvbuf、stdbuf 这类现成工具早就能调缓冲 。原文没给基准测试,性能结论是定性判断 。
对普通使用者来说,实际差别是:直连终端时日志照旧即时出现,程序 | grep 这类管道里也不会再无限期地攒着不输出。
转载说明
本文根据以下公开资料整理,原文及配图出处见下方。
评论 0
还没有评论,来抢沙发。