为什么Ruby中$stderr.sync设为false后重定向到文件输出顺序异常?
问题原因分析
这个问题和常见的stdout、stderr混用导致的顺序问题完全不同,本质是Ruby解释器底层异常输出绕过了Ruby层的IO缓冲机制导致的时序差,具体原因如下:
$stderr.sync是Ruby IO流的同步开关:当设置为true时,所有输出操作会立即刷新缓冲区,直接写入目标设备;设置为false时,输出内容会先暂存在IO缓冲区中,等待缓冲区满、进程主动调用flush、或者IO流关闭时才会真正写入底层文件。- 默认情况下Ruby的
$stderr的sync属性默认为true,所以你注释掉第一行代码时,warn 'warn'和$stderr.puts 'err'的内容会立刻写入文件,后续抛出的异常信息自然排在最后,顺序正常。 - 当你主动设置
$stderr.sync = false后,输出缓冲逻辑发生变化,直接导致顺序错乱:- 代码中的
warn 'warn'和$stderr.puts 'err'内容会先暂存在Ruby层的IO缓冲区中,不会立刻写入重定向的目标文件 fail触发未捕获异常时,异常栈信息是由Ruby解释器底层直接调用系统接口写入stderr文件描述符,完全不会走Ruby层的IO缓冲逻辑,所以这部分内容会直接写入err.log- 进程退出前,Ruby才会刷新所有未写入的IO缓冲区内容,把之前攒的
err追加到文件末尾,最终就出现了异常信息排在err前面的现象
- 代码中的
- 不重定向到文件时顺序正常的原因:当stderr指向终端(TTY)设备时,系统默认采用行缓冲策略,遇到换行符就会自动刷新缓冲区,所以
$stderr.puts 'err'输出的带换行的内容会立刻刷入终端,不等异常抛出就已经完成写入,因此顺序不会乱。
内容的提问来源于stack exchange,提问作者Inversion
相关产品推荐
相关产品推荐

