默认cin因同步C标准流、频繁函数调用与状态检查,处理千万级整数时开销巨大,实测比fread慢5–10倍;必须用ios::sync_with_stdio(false)和cin.tie(nullptr)优化,或直接fread手动缓冲读取。

为什么 cin 读千万级整数会慢到卡死
默认 cin 是同步 C 标准流的,每次调用都要检查 stdin 缓冲区、做格式解析、类型安全检查,还带异常抛出逻辑。对千万级 int(比如 1e7 个),这相当于执行千万次函数调用+锁+状态判断,实测比 fread 慢 5–10 倍。
关键不是“能不能关”,而是必须关——否则根本达不到 I/O 瓶颈,CPU 都在等 cin 自身的开销。
-
ios::sync_with_stdio(false)关闭同步(必须在任何输入前调用) -
cin.tie(nullptr)解绑cin和cout(避免每次cin后自动 flushcout) - 别混用
scanf/cin:一旦调用了scanf,sync_with_stdio(false)就失效
用 fread 手动缓冲读入整数数组最快
绕过所有流封装,直接从 stdin 文件描述符批量读字节,再按需解析。适用于纯数字、空格/换行分隔的场景(如 OJ 输入)。
核心思路:一次 fread 读几千字节进缓冲区,用指针逐字符解析数字,跳过空白,转成 int 存数组。
立即学习“C++免费学习笔记(深入)”;
- 缓冲区大小建议设为
1 (64KB),太小频繁系统调用,太大无益 - 解析时用
ch - '0'比atoi快得多;注意负号和多位数 - 不要用
std::string或std::vector::push_back在循环里动态扩容——预分配好数组
示例片段:
static char buf[1 << 16];
static int *a = new int[10000000];
int len = fread(buf, 1, sizeof(buf) - 1, stdin);
buf[len] = 0;
char *p = buf;
int i = 0;
while (*p) {
while (*p == ' ' || *p == '\n') p++;
if (!*p) break;
bool neg = false;
if (*p == '-') neg = true, p++;
int x = 0;
while (*p >= '0' && *p <= '9') x = x * 10 + *p++ - '0';
a[i++] = neg ? -x : x;
}
getchar_unlocked 适合单线程、Linux 环境下的极致优化
这是 GNU libc 提供的非线程安全版 getchar,省去了锁开销,在单进程读标准输入时比 fread 缓冲解析还快约 10–15%。
但注意:getchar_unlocked 不是 C++ 标准函数,Windows 下不可用,且多线程环境下会崩溃。
- 只在明确单线程、Linux、追求极限性能时启用(如 ACM 现场赛)
- 仍需手动跳过空白、处理负号、防溢出(尤其
int边界) - 别和
cin/scanf混用——它们内部也用getchar,会破坏状态
别忽略输入格式细节导致解析失败
快的前提是格式可控。如果输入含多余空格、空行、末尾换行、或数字间有制表符,手写解析器很容易崩或漏读。
- 用
isspace(*p)判断空白更稳妥,而不是只判' '和'\n' - 千万级数据下,少读一个数可能让后续全部错位,务必加计数校验(如读完后检查
i == expected_n) - 如果输入含十六进制、科学计数法、浮点数,
fread解析成本陡增,此时应退回到scanf或std::cin(并接受速度损失)
真正难的不是写出最快的读入,而是让快的代码在各种边界输入下稳定不出错——尤其是线上环境无法调试时。


















