New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make stdout and stderr truly unbuffered when using -u option #74589
Comments
In Python 2 when run the interpreter with the -u option the stdout and stderr streams are unbuffered. In Python 3 they become just line-buffered. This is because initially there was no way to create unbuffered text streams. But since Python 3.3 TextIOWrapper supports unbuffered output binary stream and accepts the write_through argument which switch off its own buffering. Proposed patch makes the stdout and stderr streams truly unbuffered when run with the -u option. |
Oh, I like #1667 "If write_through is True, calls to write() are guaranteed not to be buffered: any data written on the TextIOWrapper object is immediately handled to its underlying binary buffer." I didn't know write_through. It seems like it was introduced in Python 3.7: bpo-30526, commit 3c2817b. |
While I hope that users of the -u options expect the slow-down, would it be possible to benchmark it? For example, try to write setup.py content character by character to stdout using -u or not, into a TTY, into a pipe and/or a file. I'm curious if the line buffering vs really unbuffered has a significant impact on performances. |
Writing separate lines: $ ./python -m timeit -s 'import sys' -s 'with open("setup.py") as f: s = f.readlines()' 'sys.stderr.writelines(s)' 2>/dev/null
200 loops, best of 5: 1.07 msec per loop
$ ./python -u -m timeit -s 'import sys' -s 'with open("setup.py") as f: s = f.readlines()' 'sys.stderr.writelines(s)' 2>/dev/null
Unpatched: 50 loops, best of 5: 5.89 msec per loop
Patched: 100 loops, best of 5: 3.32 msec per loop Writing separate characters: $ ./python -m timeit -s 'import sys' -s 'with open("setup.py") as f: s = list(f.read())' 'sys.stderr.writelines(s)' 2>/dev/null
10 loops, best of 5: 30 msec per loop
$ ./python -u -m timeit -s 'import sys' -s 'with open("setup.py") as f: s = list(f.read())' 'sys.stderr.writelines(s)' 2>/dev/null
Unpatched: 5 loops, best of 5: 49.2 msec per loop
Patched: 2 loops, best of 5: 137 msec per loop |
Hum. It has an huge impact on performances. Would it make sense to have two command line options to choose between unbuffered and line buffered? The C setvbuf() function uses these constants:
|
Note that if output by lines, the patch speeds up the output! Actually the output is fast enough with buffering and without. The only slowdown is exposed when output by characters, but this is uncommon case. And if you output by characters (in case of drawing a progressbar or like), then perhaps you want the characters been displayed immediately, without buffering. See also bpo-13601. |
If there is a need in making redirected stdout line-buffered, a new option can be added in separate issue. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: