二进制兼容性:现在或永不

Titus Winters在21工作组(WG21)-C ++语言标准化委员会中的出版物的翻译。 作者讨论了一个重要问题:支持向后二进制兼容性或ABI(应用程序二进制接口)。

在WG21的过去几年中,我一直在积极地推动进步是比向后兼容更重要。 但是我本人不再相信这一点,尤其是在保持二进制兼容性(ABI)方面。 在最近的三个版本(C ++ 14,C ++ 17和C ++ 20)中,ABI一直很稳定。 即使WG21决定打破C ++ 23中的ABI向后兼容性,我们在许多平台上提供二进制兼容性已有10多年了。 我认为, Hyrum定律在软件系统的大规模变更中占主导地位。 现在,您无法确定有多少用户对ABI标准库的稳定性(无论多么明智,显式或隐式)牢牢地“缝在了子皮质中”的假设,可能是全世界一半的C ++开发人员。


如果我们决定“破坏” ABI,我会列出WG21在该语言中可以解决的问题。 而且我不能自信地说返工的总成本(仅需要执行此列表)就相当于在整个生态系统中违反ABI的成本。 我们在API的一致性,标准库代码的质量等方面看到了许多小的改进,但是毫无疑问,没有任何“突破性”更改可以证明普通开发人员可以为此付出代价。 也许我们会得到更好的标准实施,有机会解决当前不符合标准规范的实施问题。 但是,我的清单上没有一项改进显然值得。


更重要的是,由于ABI的限制,我们无法消除重大的性能损失。 我们无法摆脱按值传输unique_ptr的巨额成本[钱德勒在CppCon 2019上的性能,将在稍后发布],我们无法更改std :: hash或该类在unordered_map的内存中的放置,而不会强迫所有人重新编译所有内容。 多年来,对散列的性能进行了广泛的研究,并且考虑到表中搜索的优化和适当的散列,我们有信心可以提供与API兼容的unordered_map / std ::散列实现,并可以提高 200-300%的性能 。 但是ABI限制不允许这样做。 关于优化和调整std :: string的SSO的其他研究表明,性能有了显着提高(微基准测试和缩放比例为1%)-API不受影响,但是ABI限制不允许这样做。

被ABI专门阻止的生产力的总损失达到几个百分点-可能高达5-10%。 这不是整个生态系统不能没有的事情,但是对于某些组织(其中包括Google)来说,这可能是不可接受的。 当然,这是比C ++可接受的更大的性能损失:请记住,这是一种语言,它声称它没有为提高生产率的竞争对手留出空间。 大多数用户似乎并不担心这种性能下降:对于那些关注绝对性能的用户,还有其他哈希表实现。 在很少的任务中,与传递unique_ptr值相关的一般效率低下和ABI语言的其他问题就变得尤为重要。 需要最高生产力的组织可以使用非标准库和非标准配置工具按自己的方式做(并做到)。 这是自然的,必须清楚地理解。



ABI的更改将影响相对大量的用户。 我怀疑这些用户中有很大一部分不会怀疑他们对ABI的依赖程度如何。 在Google服务器的生态系统中,几乎所有东西都是从源头收集的,几乎没有外部依赖关系,而且进行大规模重构的机会要好于平均水平。 但是即使对于我们来说,最近对标准库进行的ABI突破性更改也花费了5到10个工程年。

可以在“ 千禧工程师 ”中保守地估计破坏整个C ++生态系统的ABI向后兼容性的总成本:协调世界上每个插件,.so或dll提供商的重建将需要大量的人力资源。 加上由于C ++ 20模块而导致的生态系统分离,在C ++ 23的开发和实施时间表中更改ABI可能导致生态系统的严重分离。



有许多问题无法通过此讨论来回答。 我们要持续多长时间,以至于将ABI从仅有用更改为关键需求? 如果我们明确选择ABI稳定性支持,那么在何时以及何时出现这样的关键需求时,变更的成本将是多少? 如果像Spectre和Meltdown这样的安全问题需要更改调用约定,那么C ++克服此里程碑需要花费多少费用? 是什么比例的开发人员使用C ++,因为我们声称将性能放在首位? 更糟糕的是:C ++可以声称是最快的语言多久而不必进行此类优化?


如果我们有意识地不允许或不想更改ABI,则必须大声说出这一决定。 我们必须明确地说,这是一种使ABI稳定性高于生产力的最后百分之几的语言。 我愿意争辩说,实际上,过去几年就是这种情况。 我们需要让用户知道对我们的期望,并让他们知道,如果需要性能,则期望诸如Boost,Folly或Absail之类的库做出正确的选择。 但是,这对于解决语言本身中与ABI相关的限制(如传输unique_ptr的成本)没有任何帮助。 标准库在此开发模型中仍然具有重要意义:标准库是我们用于兼容性和稳定性的工具。 这可能需要改变重点和发展方向:我们可能希望在变化的条件下进行更多的灵活性设计,而不是“干净”的性能。


如果我们认为性能比ABI稳定性更重要,那么我们必须立即决定何时确切地“打破”向后兼容性,并尽一切可能使生态系统接受这种变化。 并明确并大声宣布我们正在采取这种方式。 您需要了解,这些更改之间所花费的时间越多,它们将变得越昂贵-因为随着时间的流逝,对ABI的依赖将越来越多。 我们的“实施者”非常清楚地表明,破坏兼容性的C ++ 11更改既痛苦又昂贵。 避免重复这种成本的愿望是很自然的,但是您需要选择:要么不重复成本(因为我们不更改ABI),要么降低成本。


本质上,WG21有三种可能性:

  1. 在C ++ 23或C ++ 26中,决定更改ABI的发行版无关紧要。 警告人们并立即开发工具和诊断程序,以帮助确定将要破裂的地方。 重点关注更一致的做法和工具,以支持将来的ABI更改。 使用户暴露于更改ABI的后果是不符合特定实施者的利益的;如果其他实施不这样做,则为了将来用户的利益,更改ABI应该是一项协调的活动。 理想情况下,您需要破坏所有内容-明确说明以C ++ 23模式编译的代码与以前模式下编译的代码不兼容。 如果某人可以不进行重建而其他人会在布局或运行时出现错误-这只会增加误解和失望。
  2. 决定我们通过规范当今的实践来争取ABI的稳定性。 多年来,标准实施者有权否决破坏ABI的变更就是这种情况-我们已经将ABI向后兼容性设置为高于设计整洁度和性能。 如果我们认识到这一点并清楚地告诉用户,那么生态系统将会更好。 对于那些需要压缩性能的最后一滴而又不需要标准提供的稳定性的用户来说,附加库的价值将会增加。 其他面向性能的语言可能会挑战我们将来的地位。
  3. 无法选择方向并保存现状。 这对我来说是最坏的情况:我们继续隐式地更加关注ABI向后兼容性。 我们说“性能”,并投票“二进制兼容性”。 这种不和谐损害了生态系统,并意味着在语言的优先顺序上缺乏共识。 我衷心希望,通过实施者和总干事的努力,我们将达成必要的共识。

我认为,第一种选择更适合于需要最大性能的用户,但它给生态系统带来了难以置信的成本,并且将来可能导致语言的碎片化。 一个选项№2 - 无聊,负责,值得选择:黯然承认,我们在房间的角落里画满自己和尽量减少相关损失。 选择第3个选项意味着不进行管理,我祈祷这将避免:任何明确的选择都比当前的不和谐和无法就长期目标的选择达成共识更好。

我知道,我们已经通过许多看似无为的小举动达到了现在的位置。 在过去的十年中,没有发生任何改变可以证明违反二进制兼容性的理由,但是保持向后兼容性的隐含策略已经破坏了生态系统。 但是,通过明确采用这样的策略,我们将为C ++逐步退出舞台开辟另一种可能性:您不能成为面向系统,面向性能的语言,从而为提高生产率的语言留出了很大的空间。 从理论上讲,每个供应商都可以决定在将来的任何发行版中“打破” ABI,但是总体思路似乎有所不同。 我确信该标准的实施者和WG21的实施者之间需要进行讨论和达成共识:我应该选择哪些优先级?

Source: https://habr.com/ru/post/zh-CN474294/


All Articles