import sys
sys.stdout.write("stdout1 ")
sys.stderr.write("stderr1 ")
sys.stdout.write("stdout2 ")
sys.stderr.write("stderr2 ")
print()
string = ""
for i in range(10):
string = string + str(i) + "\n"
print(string)
在使用 python test.py
执行时,应该是有开启缓冲区的,不加上后面的 print 部分,输出顺序是 stderr1 stderr2 stdout1 stdout2
但是为什么加了后面的 print 部分输出变成了
stdout1 stdout2
0
1
2
3
4
5
6
7
8
9
stderr1 stderr2
stderr 不是无缓冲的么,不应该直接就输出出来在最前面么?
1
kkk330 2019-01-15 14:16:19 +08:00 1
https://docs.python.org/3/library/sys.html#sys.stderr
里面有提到 When interactive, stdout and stderr streams are line-buffered. Otherwise, they are block-buffered like regular text files. You can override this value with the -u command-line option. ```shell python3 test.py python3 test.py &> buffer.log python3 -u test.py ``` 顺便, 也可以看看 python2 的表现, 我这边测试了下是有差异的 |
2
kkk330 2019-01-15 14:27:54 +08:00 1
再补充下, 行缓冲是关键, 如果你在 sys.stderr.write 里加上\n, 那么你的输出就直接是符合预期的
|
3
OhYee OP @kkk330
我确认了下我是有开缓冲区的,没有加-u,PYTHONUNBUFFERED 也是空的 如果按照缓冲区的理解,输出结果应该是这样才对 ```python stderr1 stderr2 stdout1 stdout2 0 1 2 3 4 5 6 7 8 9 ``` stderr 明明没有用缓冲区直接输出,竟然反而比走缓冲区的 stdout 还慢。 |
5
OhYee OP 把 print 换成 sys.stdout.write 符合预期了,所以说 print 不是一般意义的 stdout 么
|
6
kkk330 2019-01-15 14:38:06 +08:00 1
是行缓冲的原因, 可以一步一步看
sys.stdout.write("stdout1 ") # stdout 里变成了"stdout1 " sys.stderr.write("stderr1 ") # stderr 里变成了"stderr1 " sys.stdout.write("stdout2 ") # stdout 里变成了"stdout1 stdout2 " sys.stderr.write("stderr2 ") # stderr 里变成了"stderr1 stderr2" print() # stdout 里变成了"stdout1 stdout2 \n" 因为是行缓冲, 发现了\n, 所以就 flush 到 tty 了 ..... # 代码最后这里执行完了, stderr 仍然没有\n, 因为程序结束了, 还是会被 flush 出来, 所以 stderr 在最后输出 |
7
kkk330 2019-01-15 14:39:23 +08:00
print 自带\n
也就是 sys.stdout.write("xxxxx\n")等效于 print("xxxxx") |
8
OhYee OP stderr 不是无缓冲的么?他不应该直接输出不用等\n 么
|
10
kkk330 2019-01-15 14:45:56 +08:00 1
"When interactive, stdout and stderr streams are line-buffered."
你应该是直接在终端里执行的命令, 因为是 tty, 所以属于交互式的, 所以是行缓冲 |
11
kkk330 2019-01-15 14:46:33 +08:00
我前面还故意列了几个执行方式让你看看他们的表现的...
|
12
swulling 2019-01-15 14:47:30 +08:00 1
@OhYee stderr 在 Python3 是 line-buffered 的,在 Python2 是无 buffer 的
从 print()看,你这个是 Python3 吧,一楼说的很清楚了 |
13
OhYee OP @kkk330
python test.py 运行的 不是直接终端运行的。 别的地方都和我理解的一样,只有混着 print 不符合理解 感觉 stderr 的无缓冲也不是简单的无缓冲 比如针对 '''python string = "" for i in range(10000): string = string + str(i) + "\n" ''' 因为在不加-u 时, sys.stderr.write(string) sys.stdout.write(string) 可以正常输出(输出到 9999) 而加上-u, sys.stderr.write(string) sys.stdout.write(string) 两者都只能输出到 2638 |
14
OhYee OP @swulling
python3 里不也是 stdout 是 line buffer,stderr 是无 buffer 么 所以按照期望不管后面的内容有没有换行, stderr1 应该一定在 stdout2 前面吧 按照我测试的情况来看,stderr 也是 line-buffer,不过网上貌似都是说 stderr 是没有 buffer 的。 另外 13 楼的输出被截断也是 buffer 的问题么? |
15
OhYee OP @kkk330
几种执行方式的结果来看 (因为被认为是外链,所以. 后面都加了空格) python3 test. py 不符合预期,stderr 作为无 buffer 不应该在最后么? python3 -u test. py 符合预期 python3 test. py >log. txt 符合预期 python3 test. py &>log. txt 符合预期 执行结果: ``` dev@u:~$ python3 test. py stdout1 stdout2 0 1 2 3 4 5 6 7 8 9 stderr1 stderr2 dev@u:~$ dev@u:~$ dev@u:~$ python3 -u test. py stdout1 stdout2 0 1 2 3 4 5 6 7 8 9 stderr1 stderr2 dev@u:~$ dev@u:~$ dev@u:~$ python3 test. py >log. txt stderr1 stderr2 dev@u:~$ dev@u:~$ cat log. txt stdout1 stdout2 0 1 2 3 4 5 6 7 8 9 dev@u:~$ python3 test. py &>log. txt dev@u:~$ cat log. txt stderr1 stderr2 stdout1 stdout2 0 1 2 3 4 5 6 7 8 9 ``` |
16
kkk330 2019-01-15 15:09:26 +08:00
"你应该是直接在终端里执行的命令, 因为是 tty, 所以属于交互式的, 所以是行缓冲"
你在 15 楼贴的就是"在终端里执行的命令" |
17
whileFalse 2019-01-15 15:12:16 +08:00
@kkk330 学习了 谢谢
|
18
OhYee OP @kkk330
Interactive interpreter 不是指直接 python3 然后终端里写代码么 类似 $ python3 Python 3.6.7 (default, Oct 22 2018, 11:32:17) [GCC 8.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> https://docs.python.org/3/tutorial/interpreter.html 这种应该是属于 script 运行吧 另外,看了下文档,block-buffered 要怎么翻译啊, 块缓冲还是禁用缓冲? 我没有在官方文档找到百度上常见的 stderr 是无缓冲类似的解释 |
19
swulling 2019-01-15 15:42:57 +08:00 1
@OhYee https://docs.python.org/3/library/sys.html#sys.stderr
When interactive, stdout and stderr streams are line-buffered. Otherwise, they are block-buffered like regular text files. You can override this value with the -u command-line option. 你不懂英文么? |
20
OhYee OP |
21
swulling 2019-01-15 16:01:38 +08:00 1
@OhYee -u 要看哪个版本,如果是 Python 3 但是是 3.7 以下,那么 -u 也不是 unbuffered,还是 line-buffered
如果是 3.7+,那么 Changed in version 3.7: The text layer of the stdout and stderr streams now is unbuffered. |
22
OhYee OP @swulling
感谢,试了下 python3.6.7 没有问题,python3.7.1 存在这个问题 看了下两者的区别,应该就是 unbuffered 导致被截断掉了 此贴完结,感谢几位大佬的帮助 ———————————— Python3.6 https://docs.python.org/3.6/using/cmdline.html#cmdoption-u -u Force the binary layer of the stdout and stderr streams (which is available as their buffer attribute) to be unbuffered. The text I/O layer will still be line-buffered if writing to the console, or block-buffered if redirected to a non-interactive file. See also PYTHONUNBUFFERED. https://docs.python.org/3.6/using/cmdline.html#envvar-PYTHONUNBUFFERED PYTHONUNBUFFERED If this is set to a non-empty string it is equivalent to specifying the -u option. Python3.7 https://docs.python.org/3.7/using/cmdline.html#cmdoption-u -u Force the stdout and stderr streams to be unbuffered. This option has no effect on the stdin stream. See also PYTHONUNBUFFERED. Changed in version 3.7: The text layer of the stdout and stderr streams now is unbuffered. https://docs.python.org/3.7/using/cmdline.html#envvar-PYTHONUNBUFFERED PYTHONUNBUFFERED If this is set to a non-empty string it is equivalent to specifying the -u option. |