惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Fortinet All Blogs
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
有赞技术团队
有赞技术团队
www.infosecurity-magazine.com
www.infosecurity-magazine.com
大猫的无限游戏
大猫的无限游戏
爱范儿
爱范儿
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threatpost
V
Visual Studio Blog
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - Franky
人人都是产品经理
人人都是产品经理
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
The Cloudflare Blog
N
News and Events Feed by Topic
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
酷 壳 – CoolShell
酷 壳 – CoolShell
V
V2EX
AWS News Blog
AWS News Blog
S
SegmentFault 最新的问题
T
Tailwind CSS Blog
Hugging Face - Blog
Hugging Face - Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Spread Privacy
Spread Privacy
J
Java Code Geeks
博客园 - 聂微东
T
Tor Project blog
宝玉的分享
宝玉的分享
博客园 - 叶小钗
Webroot Blog
Webroot Blog
博客园 - 【当耐特】
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
H
Heimdal Security Blog
Y
Y Combinator Blog
T
The Blog of Author Tim Ferriss
MongoDB | Blog
MongoDB | Blog
I
InfoQ
Security Latest
Security Latest
Martin Fowler
Martin Fowler
Hacker News: Ask HN
Hacker News: Ask HN
P
Privacy International News Feed
C
CERT Recently Published Vulnerability Notes
Latest news
Latest news
雷峰网
雷峰网
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
Cisco Blogs
H
Help Net Security
L
LINUX DO - 最新话题
L
LINUX DO - 热门话题

WoodenRobot's Blog

Mac OS 系统无法双击使用 Chrome 浏览器打开 HTML 文件 群晖 SSH 公钥免密登录 群晖 Moments 人物识别一键修复解决方案 获取联通友华 PT952G 光猫超级密码和宽带拨号账号密码 去除 iTerm2 下 Tmux 复制模式警告 优化 oh my zsh 启动速度 优酷路由宝 YK-L1c 和 YK-L1 刷入 Breed 不死和 hiboy Padavan 固件 Zoom 直播分享 Awesome pipeline 录像和资料下载 Python 使用 Redis 实现分布式锁 [转]Python 相对导入与绝对导入 Mac 使用 Brew 升级 openssl@1.1 问题 Linux通过源码编译安装 Python3.8 家庭网络漫游指南 修复黑群晖 Moments 1.3.3-0700 版本人物识别不能使用问题 TOTOLINK A3004NS 国行刷入 Breed 不死和 hiboy Padavan 固件 Nginx 搭建 Google 镜像站 中兴 ZXHN F677V2 光猫改桥接 群晖 Video Station 支持 DTS 和 eac3 解决方案 浏览器输入 URL 后的历程
[转] Python 的 Buffer 机制
本文作者: WoodenRobot · 2019-08-20 · via WoodenRobot's Blog

本文转载于:Python的Buffer机制

环境准备

Python版本: 3.7.1(3.7以上版本)
清空 PYTHONUNBUFFERED 环境变量(默认是空的,不过以防万一还是清空下)

cmd 清空

1
set PYTHONUNBUFFERED=""

powershell 清空

1
$env:PYTHONUNBUFFERED=""

bash 清空

1
export PYTHONUNBUFFERED=""

将下面内容保存到 test.py,执行下面的语句

1
2
3
4
5
import sys
sys.stdout.write("stdout1 ")
sys.stderr.write("stderr1 ")
sys.stdout.write("stdout2 ")
sys.stderr.write("stderr2 ")

执行 python test.py, 输出 stderr1 stderr2 stdout1 stdout2
执行 python -u test.py, 输出 stdout1 stderr1 stdout2 stderr2

缓冲区

现象解释

对于 stderr,其名称是标准错误输出文件,标准里规定是无缓冲的,每次输出一个字符就直接显示到屏幕上
而对于 stdout,其名称是标准输出文件,UNIX标准里规定是行缓冲的,遇到换行或者积累到一定的大小一次性输出到屏幕上

由于默认情况下,缓冲区是开启的。
因此 stdout 的输出会先存入到一个 buffer 中,而 stderr 的内容是直接显示的,因此默认输出顺序是 stderr1 stderr2 stdout1 stdout2

当将其改为

1
2
3
4
5
import sys
sys.stdout.write("stdout1\n")
sys.stderr.write("stderr1\n")
sys.stdout.write("stdout2\n")
sys.stderr.write("stderr2\n")

由于 stdout 是行缓冲,遇到换行后也是直接输出,因此此时输出内容就是正常顺序

对于 Python 而言,其规定如下:

  • 对于 Python2.x: stdout 行缓存, stderr 是无缓冲(和规范相同)
  • 对于 Python3.x: stdout 和 stderr 都是行缓冲

关于该改动的讨论: Improve documentation of stdout/stderr buffering in Python 3.x

而对于 -u 参数:

  • 对于 3.6 以下版本: 二进制流使用 unbuffered (不使用 buffer ),但是文本流采用 line-buffer(3.6 相关文档)
  • 对于 3.7 以上版本: 全部采用 unbuffered(3.7 相关文档)

而当 PYTHONPATH 不为空,视为使用了 -u 参数

虽然输出结果与行缓冲与无缓冲的结果相同,但是仍然需要注意这里并非是如同规范那样定义

什么时候不应该使用缓冲区

一般来说,第一次接触缓冲区应该都是C语言读入部分

比如如果要有用户交互输入数据,需要分析输入内容,可能会牵扯到换行的处理

当用户一次性输入很多数据时,这些数据都会被存放在输入缓冲区内,每次使用 getchar();或者 scanf("%c", &c);会从中取出一个字符出来

这时,如果输入末尾有无效输入,比如用户多打了个空格才换行等奇怪的操作,可能会导致输入缓冲区留下一部分数据,从而导致下一次处理数据出错

这时,往往要使用 fflush(stdin);在每次读入前清空缓冲区,以确保读到的数据是用户刚刚输入的内容

在 Python 中,最常见的操作是使用 flask、django 时,后台打印 log。

当同时有两个请求送达,两个打印 log 的操作同时写入输出缓冲区,很可能你看到的就是两个 log 混杂在一起的内容,这时为了保证 log 的完整以及有序,就应该关闭缓冲区

而在Python中,关闭缓冲区有三种方法:

  • sys.stdout.flush()
  • python -u xxx.py
  • set PYTHONUNBUFFERED=""

什么时候应该使用缓冲区

缓冲区(buffer)原本是用于中和内外存读取速度不同而设计的一个缓冲

因此当读写速度与运算、处理速度不匹配时就应该使用缓冲区

如大量写入文件,尽管可以使用 "n".join(data_list) 来将数据拼接成文本一次写入,但是有时候可能会由于异步、数据结构过于复杂,需要用多个 f.write() 来写入文件,这时就需要使用 buffer

将要写到文件的数据先存入内存中,关闭文件时一次性写入,从而减少了 io 操作次数

另外,引起该篇博文的原因代码是:

1
print(";".join([str(i) for i in range(10000)]))

这段代码在 Windows 环境下的 Python3.9 以下版本使用 python -u test.py 会导致奇怪的截断

简单解释就是 Windows 7 以下的控制台对写出有限制(64KiB),因此 python 会尝试将输出内容除以 2 来输出
最终导致输出内容被截断

该“特性”将在Python3.9被移除
相关讨论: StackOverflow: Why does this code print a different result between Windows and Linux?

参考资料