fast_io

English

早期的发现

我构建全新 I/O 库的兴趣始于高中时期。在浏览网上的性能基准 并进行我自己的测试时,我发现 ifstream 和 stdio 都慢得令人痛苦。在许多情况下,相比把整个文件直接读入内存并手工解析, 它们至少慢 5 倍,在某些平台上甚至 慢 10 到 100 倍。

这种低效让我确信,C++ 中的标准 I/O 设施 在根本上有缺陷,需要彻底的重新思考。

泛型编程 vs. 面向对象

我非常欣赏 C++ 标准库容器与算法中所使用的 泛型编程范式。它们展示了模板如何 同时提供灵活性与性能。然而,C++ 中的 I/O 却显得 格格不入:iostream 严重依赖面向对象编程, 其核心是虚继承。这种设计选择带来了复杂性与低效, 与语言其他地方泛型编程的优雅形成了鲜明对比。

格式字符串的问题

另一个主要的不满是它对格式字符串的依赖。 我一直认为它们是多余且不安全的。我多年使用 Lua 编程的经历,特别是在开发《魔兽世界》插件时, 给了我不同的视角。Lua 的默认做法常常比 C++ 更正确, 尽管 Lua 本身也有它的缺陷。

我逐渐相信格式字符串应当被彻底消除。无论你如何约束它们—— 即使在编译期——它们依然脆弱。宏、代码生成器, 甚至 AI 生成的代码都能重新引入格式字符串漏洞。 复杂性从未真正消失。在我看来,格式字符串是一个万亿美元级的历史错误, 堪与臭名昭著的 gets() 函数相比。既然 gets() 本身就是 stdio 中的一个 I/O 函数,这只会进一步强化我的信念: 整个 stdio 系统是极其危险的。

fast_io 的诞生

2013 年,当 Bjarne Stroustrup 在 CppCon 上介绍 concepts 原型时, 我有一个突破性的想法:为什么不用 concepts 重写整个 I/O 子系统呢?那一刻 fast_io 就诞生了——至少在 理论上。我用 GCC 的实验性 concepts 实现构建了一个早期原型, 只是为了证明这个想法是可行的。

遗憾的是,当时 concepts 还不成熟,只以 技术规范(TS)的形式存在。缺少恰当的标准库支持, fast_io 无法超越原型阶段。真正的 实现直到 2020 年前后才认真开始,那时 concepts 已成为 主流 C++ 的一部分。

打磨与哲学

即使在 2020 年之后,fast_io 仍然经历了多轮 重构。我的目标不只是让它能工作,而是让它 优秀——优雅、可移植且健壮。由于它基于 concepts, 这个库被设计为可在所有平台上工作,甚至在没有操作系统的环境中也能工作。

Herb Sutter 关于 赫布异常 的演讲进一步影响了我的愿景。 由于 I/O 是 C++ 中异常的最大消耗者之一,我意识到 fast_io 最终需要集成赫布异常,才能真正 完成它的设计。在那之前,这个库会继续 演进,随着设计成熟,API 也会逐步稳定。

向后兼容

fast_io 的一个关键设计原则是向后兼容。 这个库被构建为可与多种现有系统互操作: wine(宿主文件描述符)、NT 句柄、 Win32 句柄、POSIX 文件描述符、 stdio,甚至 iostream/fstream 中的 filebuf。我们投入了大量精力,让这些 系统在统一的接口下彼此兼容。

Freestanding 环境

由于 fast_io 意在随处可用,包括 freestanding 环境,我逐渐意识到 C++ 社区所倡导的 许多特性——异常处理(EH)、RTTI、vector、 array 等等——在宿主环境之外根本无法可靠工作。 这进一步强化了需要这样一个库:既 对 freestanding 友好,在概念上又足够现代。

展望未来

fast_io 不只是一个 I/O 库。它是一个概念验证—— 向 WG21 和更广泛的 C++ 社区展示 I/O 可以用现代语言特性 重新构想。它是对低效、冗余和过时设计模式的一次 宣言。它也是致力于构建既快速又在概念上干净的 工具的承诺。

视频介绍

下面这个演讲进一步阐释了 fast_io 背后的理念: