苹果: 密码监控服务从 Java 迁移到 Swift

在苹果公司,Swift 被大量用于构建云服务,并取得了令人难以置信的成果。去年,用 Swift 重写了密码监控服务,每天处理来自世界各地设备的数十亿次请求。与以前的 Java 服务相比,更新后的后端性能提高了 40%,可扩展性、安全性和可用性也得到了改善。

密码应用程序于 2024 年秋季推出,可帮助用户管理密码、密钥和验证码。它允许用户存储、自动填充和生成可在所有设备上共享的高强度密码,以及与可信联系人共享密码。该应用的一项安全功能是密码监控,如果用户保存的密码之一出现在数据泄漏中,该功能就会向用户发出警告。该功能有一个服务器组件,运行在基于 Linux 的基础架构上,由苹果公司负责维护。元素周期表

密码监控会定期将用户的密码与不断更新和整理的已知泄露密码列表进行核对。重要的是,这项任务是以一种周到的、保护隐私的方式处理的,绝不会向 Apple 透露用户的密码。关于如何使用加密私有集交叉协议完成这项工作的详细讨论,请参阅《Apple 平台安全指南》中的 “密码监控 ”部分。

从 Java 迁移到 Swift 是因为需要以高性能的方式扩展密码监控服务。密码监控使用的分层加密模块需要对每个请求进行大量计算,但即使在高负载情况下,整个服务也需要快速响应。

选择 Swift 提高性能

多年来,我们的团队一直依赖 Java 来支持大规模关键任务服务,因为 Java 的稳定性和性能已得到验证。然而,Java 的内存管理方法已不再符合我们不断增长的需求和效率目标。我们需要一种更高效的语言来支持我们的增长,同时减少服务器开销,而不是简单地扩大硬件资源。

在寻找替代语言之前,我们寻求调整 JVM 的方法,以达到所需的性能。Java 的 G1 垃圾收集器 (GC) 通过引入可预测的暂停时间、基于区域的收集和并发处理等功能,缓解了早期收集器的一些局限性。然而,即使取得了这些进步,大规模管理垃圾收集仍然是一项挑战,原因包括高负载下 GC 暂停时间过长、性能开销增加以及针对不同工作负载进行微调的复杂性。

我们的 Java 服务面临的挑战之一是,由于 JVM 的开销,它无法快速提供和退出实例。密码监控服务在全球范围内运行,因此,即使使用客户端技术来平滑流量分布,服务负载在一天中也会有很大波动。一天中的高峰和低谷在区域上相差约 50%。为了有效管理这种情况,我们的目标是在不同地区需求较低时缩小规模,在需求达到峰值时扩大规模。更快的启动时间是支持这种动态扩展策略的关键要求。

考虑到我们应用程序的规模和我们每天管理的流量,从 Java 过渡到另一种语言的决定并不是轻易做出的。我们评估了各种选择,发现只有几种语言可以帮助我们实现目标。你可能会认为苹果会自动选择 Swift,但我们却惊喜地发现,它非常适合像我们这样基于云的服务的独特需求。Swift 的语法表现力强,易于学习,而且可以提供必要的性能改进,以满足我们计算工作负载的需求。我们决定进行一次重大飞跃,开始使用 Swift 重写密码监控后台。

我们使用 Swift 开发的经验

我们开始使用 Swift Web 框架 Vapor 重写我们的服务,该框架提供了路由、控制器和内容模块,我们可以在这些模块的基础上进行开发。我们的服务有一些额外的要求,这促使我们创建了一些具有基本功能的自定义包:对于实现密码监控、审计、配置、错误处理和自定义中间件至关重要的椭圆曲线操作。

Swift 给我们留下深刻印象的一个重要方面是它对协议的强调。在 Java 中,我们严重依赖继承,这会导致复杂的类层次结构和紧密耦合。Swift 的协议和泛型方法允许类、结构体和枚举共享通用协议,从而促进了模块化和可重用性,使代码库更具灵活性和可扩展性。这种思维方式的转变鼓励我们从行为而非具体类的角度思考问题,从而使代码更简洁、更易维护。

与 Java 相比,安全是 Swift 采用独特方法的另一个领域。例如,Swift 的可选类型和安全解包机制无需到处进行 null 检查,从而降低了出现空指针异常的风险,并提高了代码的可读性。无论是确定性去分配、写时复制(CoW),还是值类型,Swift 语言设计中根深蒂固的这种安全第一的方法使其从本质上降低了运行时出错的可能性。

Swift 的异步/等待支持是一个很好的补充,它简化了我们处理异步任务的方式。以前,管理异步操作往往需要复杂的回调模式或外部库。Swift 的 async/await 语法简化了这一过程,使其更直观、更不易出错。我们现在可以编写读起来像同步代码一样的异步代码,从而实现更可读、可测试和可维护的并发处理,这在高负载、多线程环境中尤为重要。

总的来说,我们使用 Swift 的体验非常好,我们完成重写的速度比最初预计的要快得多。Swift 使我们能够编写更小、更简洁、更具表现力的代码库(代码行数减少了近 85%),这些代码具有很高的可读性,同时优先考虑安全性和效率。

我们的服务得益于 Swift 软件包的多样化生态系统,包括日志框架Cassandra 客户端和现成的加密库。除了出色的支持系统和工具外,Swift 本身对模块性和可扩展性的强调也有助于未来的发展,并简化了我们服务特定功能所需的集成和定制。

对未来服务器 Swift 开发的启示

我们在整个开发和部署过程中对性能进行了基准测试,从而发现了 Swift 编程语言最令我们满意的 Trait–效率。

Swift 的确定性内存管理大大降低了我们服务的内存门槛。我们不仅取得了令人振奋的初步成果,而且在经过几次性能改进迭代后,我们的吞吐量提高了近 40%,在我们当前的生产硬件上,99.9% 的请求延迟低于 1 毫秒。此外,新服务每个实例的内存占用更小–只有几百兆字节–与我们的 Java 实现在峰值负载下维持相同吞吐量和延迟所需的 10 千兆字节相比,小了一个数量级。该服务在 Kubernetes 上运行,迁移带来的效率提升使我们能够释放约 50% 的容量用于其他工作负载。

我们的 Swift 实施已在生产中顺利高效地运行,因此我们为这次迁移所付出的努力是值得的。除了性能优于我们以前基于 Java 的应用程序外,Swift 还提供了更好的性能一致性、更强的安全功能和稳健的可靠性,同时还通过有效利用内存和 CPU 减少了对资源的需求。由于我们使用了更少行的模板代码和更灵活的设计模式,我们期待着简化应用程序的维护。Swift 是我们在高需求环境中构建快速、弹性和可维护应用程序的有力选择。

本文文字及图片出自 Swift at Apple: Migrating the Password Monitoring service from Java

你也许感兴趣的:

共有 228 条讨论

  1. > 与以前的 Java 服务相比,更新后的后台性能提高了 40%,可扩展性、安全性和可用性也得到了改善。

    与此类重写总是出现的情况一样,最大的问题是,这些改进是来自语言的选择,还是因为他们更新了陈旧的代码库并修复了错误/瓶颈。

    1. 由于内存消耗减少了 90%,我敢打赌,即使不是全部,也是大部分性能改进来自于此。事实上,硬件利用率仅下降 50%,这有点令人惊讶。

      降低云应用的内存消耗显然也是 IBM 一度对 Swift 感兴趣的主要原因。大多数云应用显然在大部分时间都处于闲置状态,因此在单个物理主机上可以复用的客户端数量受限于内存消耗,而不是 CPU 吞吐量。

      而使用 JIT 和 GC 的 Java 内存消耗量非常大。

      1. IBM 是一家庞大且相当分散的公司,我不认为在一些激动人心的党派之外,曾有过对 Swift 的集中推动。我想指出的是,大约在 2018 年,业界出现了 DRAM 短缺,人们开始更多地考虑数据中心工作负载中的内存保护问题。

      2. DRAM 的问题在于它不是 SRAM;成本很重要。你很难找到每个内核可用 DRAM 少于 1 GB 的部署环境,因为在这个点上,95% 的硬件成本通常是 CPU。进一步缩减成本毫无意义,所以人们不会这么做。因此,当使用 16 个内核时,无论你选择使用还是不使用,都会得到至少 16 GB 的 DRAM。如果你通过清除堆中的垃圾只使用了其中的 10%,那么虽然看起来更低更好,但如果两者都符合你可以购买的最低 1 GB/核的形状,那么实际内存支出并不一定更便宜。它可能只是没有充分利用你在每个 CPU 最低内存容量下所支付的内存资源,这并不一定是一种胜利。利用你购买的内存并不是浪费。

        每增加一个核心的内存 GB,实际上都要花费一定的成本。因此,每节省一 GB/核心,就能节省实际成本。但即便如此,每额外增加一个 GB/核,通常也要消耗 CPU 成本的 5%。因此,即使从 10 GB/核(有点多)降至 1 GB/核,也只能使硬件成本降低约 50%。由于他们没有提到这些实例有多少个内核,因此很难知道前后使用了多少 GB/内核,也就不知道内存是否真正节省了成本,如果节省了成本,那么与 CPU 成本相比,内存成本相对节省了多少。

      3. 有意思。如果 IBM 试图解决内存消耗问题,你认为他们为什么会选择 Swift,而不是同样可以降低内存消耗的替代方案?

        1. Swift 在性能、安全性和易用性方面处于良好的中间位置。

          它拥有更高级别的人机工程学,而 Rust(虽然我自己也很喜欢 Rust)等语言则不具备这些优势,也没有 Go 的许多缺陷(比如错误处理要好得多),而且相对容易上手。它的性能也与 Rust 或 C++ 相当。

          虽然它并不完美,还有一些问题,但它很快也成为我完成项目的首选语言。

          1. 我想知道这些问题是什么。我只在一个项目中使用过它,不知道它的问题有多深。只是想知道。

        2. 还有哪种足够流行且比 Java 更高效的现代语言缺乏跟踪 GC?

          Rust 和 Swift 几乎是仅有的两个选择,而且 Rust 可以说对普通的企业代码编写者来说更麻烦。

      4. 这就是为什么无服务器会在相反的一端兴起的原因(也是它如此便宜的原因)

        你不仅可以在机器层面共享内存,还可以在不同应用之间共享内存。

    2. 我通常会同意你的评论,但……

      考虑到他们的内存使用量也减少了 90%(可能是 Java GC 与 Swift AOT 内存管理的结果),似乎更有可能是语言的不同带来了收益。

      1. 出于性能考虑,JVM 倾向于尽可能多地使用内存。它并不能可靠地说明实际需要多少内存。如果还有未使用的内存,为什么要花费资源清理内存呢?

        如果内存是个问题,您可以设置一个限制,JVM 可能仍然可以正常工作

        1. 你的评论绝对正确。但是,如果您研究一下过去三四十年来 GC 性能方面的学术论文,就会发现它们几乎都得出了 GC 开销(摊销后)可以与手动分配/释放[1] 相提并论的结论,但通常都有一个不成文的假设,那就是它们拥有无限制的内存才能实现这一点。如果你研究一下在实践中你需要多少内存才不会在摊销的基础上遭受性能损失,你会得出 2-3 倍的结论,所以我认为假设 Java 需要 2-3 倍于 Swift/C++/Rust 的内存才能舒适地运行是公平的。

          实际上,在某种程度上,您可以从安卓与 iPhone 的对比中看到这一点。iPhone 使用 4GB 内存即可轻松运行,而安卓则慢如狗。

          [1]: 我并不质疑这些结果,但我也想指出,作为该领域的计算机科学研究人员,你可能是想证明 GC 有多棒,而不是相反。

          1. 安卓甚至不运行 JVM。

            > iPhone 可以在 4GB RAM 的情况下轻松运行,而安卓则会慢得像狗一样。

            这与内存无关。如果没有负载,Android 甚至连 2GB 内存都用不了,它仍然会比 iPhone 慢,因为它们在架构上做了不同的权衡。

            1. 重点是一般的 GC 成本,而不是你选择的 Java/JVM 实现。试着比较一下两款采用相同芯片组、内存为 4GB 与 8GB 的安卓手机。

              总之,这只是一个不科学的实验,只是为了给你提供一些概念–很明显,它们是两个不同的代码库。正如我所指出的,有文献可以量化这个问题。

              1. 很长一段时间以来,Android 都缺乏高质量的 JIT、AOT 和 GC 实现,而每个设备都是每个 OEM 对设备所做改动的雪花。

                除非我们确切知道设备上安装的是哪个 ART 版本,固件镜像使用了 AOSP 的哪些构建选项,以及通过 PlayStore 部署的主线版本是什么(如果使用的是 Android 12 或更高版本),否则我们根本无法从中得出结论。

                此外,由于缺乏分页和内存碎片,当没有更多内存可供使用时,iOS 应用程序往往会直接死亡。

        2. 如果这是一个很容易解决的问题,你不觉得他们早就解决了,而不是用 Swift 重写吗?

          1. 已经开发了很长时间了,没有。

            坦率地说,只需要一些积极主动的高级开发人员和诱人的能力,发布 OP 博客文章,就能得到管理层的认可。你还可以大谈使用苹果技术完成工作是多么了不起。

            我认为他们没有认真对待这件事,因为文章只提到了调试 G1GC。事实上,如果暂停时间和启动时间对他们来说真的是个大问题,他们本应该讨论 ZGC、AppCDS,甚至 Graal。甚至连 CRaC 也应该被提及。

            让 JVM 在亚秒级时间内启动并不难。这里有一个框架,它的首页上就印着这样的字样。[1]

            [1] https://quarkus.io/

            1. 没错,简历驱动开发。我记得在之前的一家公司,一小群人推动了 Go 的重写,以加快一切速度。速度的大幅提升来自于重新架构(取消了一个繁重的自定义框架,使用消息队列而不是同步处理请求等)。他们本可以更好地修复原有系统,让所有系统都能从改进中受益,而不仅仅是那些被他们砍掉的小部分。

              然后,在下一份年度报告中,他们又大谈谷歌的这项神奇技术提高了可扩展性。

              1. 简历驱动开发就是用一些乱七八糟的 Java 框架来填充简历。苹果公司使用苹果技术似乎更像是企业授权。

            2. 如果苹果不在生产系统中使用自己的技术,他们还有什么机会告诉第三方用户 Swift 已准备就绪。

              深入研究 Java 的奥秘,而不是获得 Swift 开发的第一手经验,会浪费很多改进 Swift 的机会。

              1. 如果这是一个全新的系统,我同意。

                但是,他们选择用 Swift 取代现有系统。我提到的 “奥秘 ”是很容易找到并且可以安全应用的启动选项。这就像“-O2 ”对 C++ 的魔力一样。

                当然,如果是为了使用 swift,这可能是正确的选择。但是,这并不意味着要想让 Java 变得更好就没有什么可做的了。我所描述的步骤就相当于一两天的开发工作。你认为重写需要多少时间?

                1. 苹果公司已经明确表示,他们希望尽可能多地将自己的东西迁移到 Swift 中。

                  我相信你是对的,一定有办法改进部署工作。但如果他们想减少资源使用,而使用 Swift 又与其他公司的目标一致,那么他们直接使用 Swift 就说得通了。

                2. 有一次,亚马逊首席执行官被问及新竞争对手试图快速创建云基础设施的问题。他的回答是 “你无法压缩经验”。

                  通过学习第三方技术而不是应用和改进第一方技术来节省几周或几个月的时间是外行的做法。

                  > 然而,这并不意味着没有任何事情可以让 Java 变得更好。

                  苹果公司或任何选择自己的技术而不是别人的技术的人都对自己没有选择的技术欠缺绝对的公平。世界根本不是这样运转的。

                  是的,有很多公司花费大量资源优化 Java 栈,甚至与甲骨文公司的 Core Java 团队合作改进 JVM 内部结构。但这些公司只是核心技术的用户(尽管是重度用户),而不是竞争技术的开发者。苹果公司不是这些用户中的一员,他们是开发者。

                  1. > 是的,公司花费大量资源优化 Java 栈的故事不胜枚举。

                    这不是我所提倡的。有时重写是必要的。

                    我所提倡的是使用一些有据可查、相当知名的 jvm 标志,这些标志并不特别麻烦。

                    jvm 确实有无穷无尽的旋钮,但其中大部分你都不应该去碰,而应该让启发式方法来完成它们的工作。我提到的这些标志并非如此。

                    例如,将 g1gc 换成 zgc,就能解决他们对负载下 GC 影响的主要抱怨之一。如果实时集没有接近最大堆大小,那么暂停时间就会低于毫秒。

                    > 这似乎是苹果公司或任何选择自己技术而非他人技术的人的一贯作风,他们对自己没有选择的技术欠缺绝对的公平。世界根本不是这样运转的。

                    之所以有这种说法,是因为 Java 是一种非常知名的技术,很容易招聘(你引用的亚马逊就大量使用 Java)。而且苹果公司已经采用了 Java 并用它编写了产品(我怀疑他们有好几种)。

                    如果这篇文章是对 Java 和 swift 的通用基准和比较,我就不会说这些了。我不会因为苹果公司说 “我们正在用 swift 重写,以尽量减少内部使用的语言数量,改善 swift 生态系统 ”而指责他们。

                    我对他们试图将此作为性能限制的绝对必要条件来推销的做法表示反对,同时对其原因做出了令人质疑的陈述。

                    而且,“我们通过 Swift 的默认编译器选项获得了我们想要的性能”,在文章中指出需要调整一些标志也是合理的。而使用 Java 要达到同样的效果,则需要对默认设置进行多次修改”。我个人认为这并不令人信服,但这是诚实的,而且会动摇那些希望 “只需工作 ”而无需费力的人的想法。

                  2. 我还记得苹果公司开发了自己的 JVM,将 WebObjects 从 Objective-C 移植到 Java,甚至将其作为主要应用语言的日子,当时还不确定他们生态系统中受过 Object Pascal/C++ 教育的开发人员在过渡到 OS X 时是否会去学习 Objective-C。

          2. 在 IBM,没有什么事情是简单明了的。

            几十年前,我曾与三名 IBM 员工合作开发一个客户项目。在讨论备份解决方案时,其中一人建议我们每天将所有客户数据迁移到 DB2 中,然后备份 DB2 数据库。

            我问为什么不能直接备份客户现有的数据库,而跳过迁移步骤。回答是什么?“因为我们的商业目的是销售 DB2。

          3. 你要根据你所拥有/能够得到的进行调整。内存较小的机器往往 CPU 速度较慢。这可能导致无法调整 CPU 和内存的使用率(接近 100%)。

            是的,苹果公司庞大而富有,因此他们可以用较少的内存获得较快的机器,但他们很可能还有其他不同要求的任务需要在相同的硬件上运行。

          4. 没有人会因为修复漏洞而升职。重写整个系统是实现这一目标的好方法。

          5. 但这样你就得不到晋升机会和 “有趣 ”的工作!

      2. 典型的经验法则是,要从跟踪 GC 中获得良好的性能,需要将内存使用量增加一倍,因此 90% 的降低表明他们在语言切换的基础上进行了重大改进。

        1. 90% 的降低并不一定只与 GC 有关。

          根据我的经验,即使与其他垃圾回收语言相比,Java 也是一个内存大户(这是我对该语言的主要不满)。

          我认为很大一部分原因在于,如果不考虑原始类型,Java 中几乎所有东西都是堆分配的对象,而且 Java 对象相当 “肥胖”:在 64 位架构上,每个实例的头都在 96 到 128 位之间[1]。这是……一个很大的数字。只需缩小头(上述链接的主题),就能减少 20% 的堆使用量,并缩短 CPU 和 GC 时间 [2]。

          我希望,一旦出现值类[3][4],并且库开始使用它们,我们就会看到普通 Java 应用程序的堆使用量大幅减少。

          [1] https://openjdk.org/jeps/450

          [2] https://openjdk.org/jeps/519

          [3] https://openjdk.org/jeps/401

          [4] https://www.youtube.com/watch?v=Dhn-JgZaBWo

          1. 与其他语言相比,Java 的 GC 方法有些独特。它有多个 GC,而且几乎所有 GC 都是移动收集器。这就意味着,JVM 很少会释放它已占用的内存。一个大的峰值意味着它将保留峰值的内存量。

            许多其他 GCed 语言,如 swift、CPython、Go,都不使用移动收集器。相反,它们会分配和固定内存,并在不使用时释放内存。

            JVM 方法的好处是,在几乎所有的收集器上,堆分配都非常快。一般来说,分配时只需检查是否有可用空间和指针碰撞。对于其他语言,你最终一定会使用由 malloc 实现提供的 skiplist 和/或 arena 分配器。就性能而言,大致为 O(log(n))对 O(1)。

            别误会我的意思,对象头确实占用了相当大的内存。大约是其他语言的两倍。不过,很多人都会混淆 JVM 向操作系统申请的内存(因此操作系统也会报告)和 JVM 正在使用的内存。这是两码事。

            碰巧的是,对于移动收集器(如 JVM 通常使用的收集器)来说,更多的保留内存意味着更少的垃圾收集次数和垃圾收集时间。

            1. 移动式垃圾收集器并不罕见,其他语言也有。比如 C# 就有,OCaml 和 SBCL 也有。

              我知道移动式垃圾回收器需要权衡利弊,但其规则是内存使用量翻倍,而不是像减少 90% 所暗示的内存使用量翻十倍。

            2. > 许多其他采用 GC 的语言,如 swift

              Swift 采用的不是垃圾回收,而是引用计数。因此,当内存不再处于作用域中时,它就会被立即释放。

              1. 引用计数是垃圾回收的一种形式。

              2. 在讨论这些问题时,人们真的应该多了解一下 CS。

                第 5 章,https://gchandbook.org/contents.html

          2. 如果说 Java 的 128 位对象头已经相当肥大,那么 CPython 的对象头又该用什么形容词呢?[]大约是一整行缓存。琐碎的 Python 对象几乎没有这么小的。

        2. 我还记得 20 年前的 2 倍规则 – 你知道情况是否发生了变化吗?如果现在本地性更重要,那么跟踪 GC 的性能可能永远比不上引用计数。要么使用 2 倍的内存并破坏缓存,要么使用更少的内存并花费过多的 CPU 时间进行收集。

          1. Java 采用 AOT 编译已经有一段时间了,因此传统的 GC 及其巨大的开销不再是绝对必要的。即使是 AOT Java,在内存使用方面也可能会落后于 Swift 或任何其他本地编译的语言,但应该不会那么剧烈。

            至于性能和本地性,Java 的即时指针重排序/压缩功能在某些算法上甚至比某些编译语言更具优势。很难说这是否与苹果公司基于其服务的网络框架有关,但我不会因为 Java 使用了 GC 就不考虑它的定位优化。

            1. 虽然像 Excelsior JET 和 Websphere Real Time 这样的工具链只有那些愿意花钱购买 AOT 编译器和 JIT 缓存的公司才能使用,但从 2000 年左右开始,还是有一段时间可以使用。

              现在,所有主要的免费啤酒实现、OpenJDK、OpenJ9、GraalVM 和 ART 堂兄弟都提供 AOT 和 JIT 缓存。

              即使没有 Valhala,使用 Panama 也能玩出不少花样,可以手动创建类似 C 语言的 struct 内存布局。

              是的,它有很多模板,但我们可以用 AI(也许)绕过这些模板,或者直接编写 C 声明并将 jextract 指向它。

            2. > Java 采用 AOT 编译已经有一段时间了,因此传统的 GC 及其巨大的开销不再是严格意义上的必需品。

              你是说它会进行逃逸分析并堆栈分配它能分配的?这肯定会有帮助,但不会消除 GC。还是你在想别的什么?

              再仔细想想,我记得 Java 也有一些不利于性能的设计决策(例如,几乎所有东西都是对象,数组不打包,动态分派无处不在)。Swift 则不需要处理这些遗留问题。

              1. Java 也有很多制作抗优化代码的文化,所以这就涉及到一个问题:你说的是语言本身还是各种广泛使用的库,尤其是如果这些库已经足够老,其设计模式是围绕美学或现在的语言限制而非性能。

                我曾多次用 Python 代替 Java 代码,每次都能看到内存使用量减少了一半以上,而性能至少提高了一倍,因为代码使用了更简单的函数和结构。Java 拥有先进得多的 GC 和 JIT,但在某些时候,代码的重量和间接性会胜出。

                1. 这很有趣。我用 Quarkus 逐行重写了一个大型 Django 路由,速度快了 10 倍,而且没有使用 async 或其他东西。

                  1. 这就是我说 “文化 ”的原因–按理说,JVM 应该在这场竞争中胜出。我在一篇兄弟姐妹的评论中又写了一点关于最近的评论,但我想把它概括为 “JVM 无法阻止企业 Java 开发人员”。

                    https://news.ycombinator.com/item?id=44179589

                    1. 无论使用哪种编程语言,企业开发人员和架构师都是一样的。

                      我年纪大了,见多了企业级 C 和 C++ 开发人员。

                      你认为 DCE、CORBA 和 DCOM 这些东西是从哪里来的?

                      此外,人们指责 Java 的许多东西,在用 Java 重写之前都是作为 Smalltalk、Objective-C 和 C++ 框架诞生的。

                      既然我们是在讨论苹果,这里有一些来自苹果框架的 Objective-C ID、

                      https://github.com/Quotation/LongestCocoa

                      我还建议在将 WebObjects 移植到 Java 之前,先获取 Objective-C 中的原始 WebObjects 文档。

                    2. > 无论使用哪种编程语言,企业开发人员和架构师都是一样的。

                      这在某种程度上是对的,但我之所以把重点放在文化上,是因为在每种语言中,人们学习和传承的模式是不同的。例如,企业级 COBOL 程序员在内存中重复数据的程度并不相同,这不仅是由于硬件限制,还因为没有一种文化告诉每个年轻程序员这是应该遵循的典范风格。

                      我完全同意 C++ 也有同样的问题,但大多数企业用户都转向了 Java 或 C#,因为他们觉得编写 C++ 的社区提高了对性能敏感的开发人员的比例。Python 也有这样的问题,尤其是在 2000 年代,但很多非常严肃的架构师并不喜欢这种语言,因此他们对社区的影响并没有那么大。

                      我并不是说参与其中的每个人都很糟糕,我只是觉得有趣的是,我们喜欢谈论软件工程,但有很多主要因素基本上都是人们愿意相信的好东西。

                2.  > 我用 Python 代替 Java 代码好几次了......而性能至少提高了一倍
                  

                  你是说你让 Python 代码的运行速度是 Java 代码的两倍?两者我都写过很多。我真的很难让 Python 快速运行。我做错了什么?

                  1. 更准确地说,在部署新服务微服务时,每秒处理更多请求所使用的 CPU 不到一半。

                    这并不是 “Java 慢,Python 快”–我以为情况会恰恰相反–而是开发人员在编写一个杂乱无章的 Spring 应用程序时,以某种方式成功地抵消了 JVM 开发人员所做的所有工作,而没有做任何明显错误的事情。没有一个瓶颈,只有千刀万剐的数据访问模式、间接、非常深的堆栈跟踪等。

                    我毫不怀疑,这里有人本可以用更好的 Java 重写它,并取得重大胜利,但重写的目的是将最初由一个已离职团队编写的项目与应用程序其余部分的 Python 代码进行统一,并处理各种正确性问题。在数据模型中使用 Pydantic 不仅能显著减少代码量,还能清除输入验证中的大量不一致问题,这正是我一直在寻找的,同时还能重复使用我们的通用代码库,以实现一致性。性能上的胜利只是锦上添花,说白了,我并不认为这对 JVM 有什么影响,只是它还没有调用大语言模型(LLM) 来使代码不那么企业化的优化方法。

                    1. 好吧,我明白你的意思了。基本上,你把一个糟糕的(值得点击的)企业级 Java Web 应用程序改写成了一个合理的、可维护的 Python Web 应用程序。我很同情你。是的,我同意: 遗憾的是,我见过的垃圾 Java 企业级应用程序要比没见过的多得多。为什么呢?我也不知道。激励机制不协调。

                      作为反驳: 看看 Crazy Bob (Lee/R.I.P.) 的 Google Guice 或 Norman Maurer 的 Netty.IO 或 Tim Fox 的 Vert.x: 它们都是如何编写超精简、低级、高性能的现代 Java 应用程序的范例……但却经常被忽视,以至于要雇用廉价、低技能的 Java 开发人员来编写 “又一个 Spring 应用程序”。

                    2. > 但却经常被忽视,而去雇佣廉价、低技能的 Java 开发人员来编写 “又一个 Spring 应用程序”。

                      是的,这就是为什么我把它贴上文化的标签,因为这完全是一种商业失败,承包公司基本上都在做 “既然我们拿同样的薪水,为什么要雇这些昂贵的人呢?对语言喋喋不休没有任何意义,它不能解决业务问题,但不幸的是,这种开发存在大量惯性,很多人都是这样被训练出来的。我想,甲骨文公司的 Java 团队知道自己的心血将被一半用户埋没,一定会非常沮丧。

                    3. 在我看来,“Spring 热 ”是 Java 所遭遇的最可怕的事情。确实有一些开发人员和公司将整个语言及其生态系统贬低为 Spring。这太可悲了。我很庆幸自己在 Java 领域工作了 15 年以上,从未接触过任何 Spring 的东西。

          2. 这完全取决于具体情况,但 JVM GC 方式的一个主要优势是相关内存将倾向于集中存放。串行、并行和 G1GC 收集器尤其如此。

            假设你有一个看起来像 A -> B -> C 的对象,即使 A/B/C 的分配发生在不同的时间段和不同的分配之间,下一次 GC 运行时,当它遍历图形时,它会看到并将 [A, B, C] 放入内存,前提是 A 仍然有效。这意味着,即使内存最初看起来像 [A、D、B、Q、R、S、T、C],收集和压缩的行为也会倾向于重新定位。

            1. 理论上是这样的 — 压缩收集器会减少碎片,并能将链接对象放在彼此旁边。另一方面,引用计数存在于对象中,因此当你更改对象时,很可能已经在使用该缓存行了。

              我不知道在现代机器上哪一个更重要,这可能取决于工作负载。

              1. 问题在于内存托管而非 RC 管理。但我同意,这很可能取决于工作负载。RC 的一个主要优点是执行成本非常可预测。几乎没有外部状态会对性能产生负面影响(比如当前正在运行的 GC)。

                缺点是碎片和内存管理所需的 CPU 时间。如果您有一个 A -> B -> C 链,其中 A 是 B 的唯一所有者,而 B 是 C 的唯一所有者,那么当 A 变为 0 时,它必须执行 2 次指针跳转来取消分配 B,然后再取消分配 C(加上取消分配的区域管理)。

                JVM 移动式收集器的一大好处是,当 A 死机时,收集器无需访问 B 或 C 以取消分配它们。收集器只访问和移动实时内存。

                1. > 缺点是碎片化和内存管理所需的 CPU 时间。如果你有一个 A -> B -> C 链,其中 A 是 B 的唯一所有者,而 B 是 C 的唯一所有者,那么当 A 命中 0 时,它必须执行 2 次指针跳转来取消分配 B,然后再取消分配 C(加上取消分配的区域管理)。

                  我认为这将更加强调值类型等功能,以及以组合方式创建对象的灵活性。你可以倾向于使用更大的对象,而不是嵌套内部对象来实现功能。例如,你可以使用标记联合来表示可选性,而不是指针。

                  在 Java 中,深度 A->B->C 关系的代价来自于集合,而集合默认情况下仍然是停止的。区别在于,引用计数 GC 会在删除对象时评估这些链,而引用跟踪 GC 会评估实时对象。

                  因此,如果要创建大型瞬时数据集,那么垃圾收集对于引用计数来说是昂贵的;如果要保留大型数据集,那么垃圾收集对于引用跟踪 GC 来说是昂贵的。

        3. 这只是 GC 部分。另一个很大的区别是引用类型(Java)与值类型(Swift)。

      3. Java 运行时是一头野兽。即使另一个运行时也能做类似的事情,这也令人印象深刻,而不用考虑它可能更好的事实。即使与之不相上下,也会让我产生兴趣,也许我可以自己尝试一下。

    3. 帖子指出,面向用户的应用程序是 “在 2024 年秋季推出的”,因此推测这些服务并不是传统的。

      1. 不过,在编写 V2 时,你可以学到很多东西。你有很多现实世界的经验,知道以前的设计哪些行得通,哪些行不通,因此有很多机会来制作更适合问题的数据结构等等。

      2. 但是,他们是从头开始编写后端,还是基于一些 “com.apple.libs.backend-core…”,它们往往会带来重复的逻辑和设施,他们在所有服务器中都有吗?抑或是他们将 PoC 升级为 MVP,现在正花时间 “正确 ”重写,以支持接下来的任何功能?

    4. 我的看法是,Java 没有值类型(目前还没有),而 Swift 有,这是提高效率的主要原因。

      1. 作为一名 C# 开发人员,我想我只是想当然地认为我们有值类型。今天学到了一些新东西(Java 显然没有)。

        1. 对于基元来说有。

          对于用户定义的东西,我们最近获得了记录,这是朝这个方向迈出的一步,完整的解决方案即将推出。

            1. 基本上没有。

              即使记录也不是基于值的类型,而是仅限于类似值语义的类,例如,它们不能扩展类型,默认情况下应具有不可变行为,即修改后会创建一个新的记录实例,等等。

              理论上,JVM 可以执行逃逸分析,以确定记录的行为方式,并可以进行堆栈分配,或嵌入聚合对象的存储中,而不是进行单独的堆分配。

              C# 结构会被框起来,以适应某些情况,如调用时的对象状态参数。理论上,JVM 会注意到这种可能性,并决定从一开始就对记录进行堆分配。

              我之所以说 “理论上”,是因为我还没有追踪到这项功能是否已经实现,如果已经实现,又有哪些限制。

            2. 目前只能通过巴拿马,在本地内存段中手动创建内存布局。

              Valhala 应该会带来语言级别的支持,最大的问题是如何引入值类型,而不破坏 Maven Central 中的所有 ABI。

              这与 .NET Framework 中的整个 async/await 工程类似,即如何在不添加新的 MSIL 字节码或不需要新的 CLR 功能的情况下引入 async/await。

            3. 我不确定 C# 的结构体语义。

              JAVA 将来要获得的是不可变的数据值,其中的引用就是值。

              例如

               class Foo {
                   int a;
                   int b;
                 }
                 var c = new Foo();
              

              在 Java 中,“c ”实际上是一个引用,它最终指向 “a”、“b ”的堆存储位置。用 C++ 术语来说,可以把交互看作是 `c->b`。

              当值降落时,`c`的表示可以是(由 JVM 决定,出于各种性能原因,它可以保留旧定义)类似于 [type, a, b]。或者用 C++ 术语来说,内存布局可以类似于下面这样:

               struct Foo { int a, int b };
                  struct Foo c;
                  c.a = 1;
                  c.b = 2;[/预]
      2. 不过,您可以利用巴拿马来解决这个问题,尽管这并不是世界上最好的体验。
        在内存布局段方面,创建类似 C 语言的结构体,然后通过 Panama API 访问它们。

        1. 2025 年还有这种东西吗?有很多第三方库都提供基元集合。例如:https://github.com/carrotsearch/hppc

          1. 如果你不是特别在意内存使用,为什么要使用第三方库?

    5. 同意,这几乎总是好处所在。你可以编写软件的第二版,并从第一版中吸取经验教训。

    6. 是的!如果能深入分析性能提升的来源,这篇文章的信息量会更大。但苹果公司就是苹果公司,我想他们永远不会愿意公开其内部系统的细节,我们可能只能得到这种手忙脚乱的说法。

      1. 我怀疑这不符合博文的目的。
        我认为这篇文章的目的并不在于事后总结,找出问题所在并提出解决方案,而更像是一份小型白皮书,指出 Swift 可以在服务器上使用,并有一些不错的优势。
        因此,Java 实现的具体问题并不重要,重要的是 “虽然它做得很好,但启动起来又重又慢”。

    7. 当然,也许你能弄到钱,让一些企业尝试用相同的语言和不同的语言重写他们的业务线软件,并取得一些成果。
      我的期望是,如果你下了功夫,你就能得到实际的硬数据,而这些数据会被以后提出同样 “问题 ”的人迅速忽略,并得到同样的隐含答案。
      如果 “只要重写就会更好 ”的人真的像他们经常认为的那样是对的,那么一个很大的谜团就是 JWZ 的 “注意力缺陷青少年层叠 ”现象。在这种情况下,同样的软件被重写,一次又一次,一次又一次,但它并没有变得更快,甚至没有修复很多严重的错误。

      1.  如果 “只要重写就会变得更好 ”的人真的像他们经常相信的那样正确的话
        

        一般来说,数千年来的技术进步证明了这一点。当然,在短期内,我们可能会看到一些下滑,这取决于人才/专业技能,但随着教育的发展和对所学知识的更新应用,一般来说,这是正确的。

      2. 对于其他也不了解 CADT 的人来说:https://www.jwz.org/doc/cadt.html

        我承认,在我职业生涯的不同阶段,我也曾是级联的一部分。

    8. 想象一下 Rust 或 go 能取得什么样的成就吧

      1. 在强制性高成本抽象方面,Go 与 Swift 相似。

        只有 Rust(或 C++,但不安全)才有大部分零成本的抽象。

        1. Swift、Rust 和 C++ 实现零成本抽象的底层技术(主要是全特化泛型)都是相同的。Swift 的区别在于,泛型也可以不经专用化而执行(这使得泛型方法可以在稳定的 ABI 边界上调用)。

          Swift 和 Rust 还允许它们的协议被动态擦除和调度(在 Rust 中是动态的,在 Swift 中是任意的)。但在这两种语言中,这更像是 “当你需要时 ”的事情,泛型才是首选工具。

          1. 大致如此,但 stdlib 和库会有偏差。实际上,与 Go 或 Swift 相比,Rust 和 C++ 中更常见的抽象实际上是零成本的。

            这并不是坏事,我只是想指出,Go 与 Swift 相比并不具备性能优势。

        2. Swift 现在也有了(不可复制类型)。

        3. > 只有 Rust(或 C++,但不安全)才有大部分零成本的抽象。

          事实并非如此。这对 Rust 来说是很好的营销炒作,但任何拥有优化编译器(JIT 或 AOT)的语言都有大量的 “零成本抽象”。

    9. 我总是喜欢看到这样的评论。在 JVM 上,你会使用像 Spring 这样的垃圾,并过度设计一切。20 种类型、接口和对象,只为在内存中保留一个字符串。

      JVM 也喜欢内存,但可以定制得看起来还行,但还是不如对手。

      1. 我百分百确定你可以在 Swift 中做到同样的事情。

        1. 这不是技术问题,而是文化问题。不同的社区约定俗成。

        2. 当然,你也可以用 php 写出漂亮的代码,或者用 Java 写出漂亮的代码。

          历史、标准库和所有传统教程才不会从网络上消失。

        3. Swift 在反射方面的限制实际上使得创建典型 Java 风格的混乱 IOC 容器等变得出奇的困难。

            1. > 听说过 Swift 宏吗?

              是的,我在 Swift 的日常构建边缘生活了几年,包括宏开发期间,我确实听说过宏。

              > 你知道 Java EE 从何而来吗?

              完全了解历史。

              问题的关键在于:使用 Swift 要想做出 JVM 应用程序通常会出现的那种 Spring 风格的混乱是非常困难的(当然也有例外: 我通常建议人们像马丁-汤普森(Martin Thompson)而不是马丁-福勒(Martin Fowler)那样编写 Java)。此外,_人们就是不这么做_。我想,你可以形象地计算出使用 IOC 容器的 swift 服务器应用程序的百分比。

              1. 首先,Swift 服务器应用程序的数量必须增长到与企业架构师关注的实际相关数字。

                然后我就可以开始计算了。

                1. 这就是我使用百分比而非绝对值的原因。就 Java 而言,我所见过的每一个应用程序都是一团糟。对于 Swift,我见过的 40-50 个应用程序中只有 0 个是垃圾。

                  1. 要想让 Swift 在《财富》500 强的 Linux 和 Windows 服务器上成为 “狗屎”,就必须有人开始大批量生产,而不考虑百分比。

                    当有足够多的人在采用曲线之外使用这些语言编写代码时,任何语言都可能成为 “狗屎秀”,这些人包括拥有麻省理工学院学位的 Letcoder,将单个函数打包发货的六周新兵训练营学员,以及在白板上使用 SAFe 设计未来架构的架构师。

                    当 Swift 最终进入这个世界时,我们就可以比较一下,除了舒适的苹果生态系统之外,它还有多少内容能够在世界范围内被广泛采用。

      2. 一样–在每一种语言中都有不称职的团队

  2. 我希望能在 WWDC 上听到一些好消息,以促进 Xcode 以外的编辑器(VSCode、Neovim 等)的快速开发。去年,他们说 “我们需要满足后端开发人员的需求”,并宣布了改进 sourcekit-lsp 和其他工作的计划。

    1. 在我看来,苹果公司在 “满足 X 的需求 ”方面有着良好的记录。他们可以让 Xcode 跨平台,但永远不会。

      1. Xcode 可能是世界上最大的 MacOS 原生应用程序的前……3?世界上最大的 5 个 macOS 原生应用程序之一。

        要让它实现跨平台,要么从头开始重新实现,要么在其他平台上重新实现 AppKit,做一个 Safari on Windows 级别的小把戏。

        1. > 在其他平台上重新实现 AppKit 的 Safari on Windows 级诡计

          我对此很好奇,所以下载下来看了看。看起来他们并没有真正发布 AppKit,至少没有发布单独的 DLL,但他们确实发布了 Foundation、Core Graphics 和其他一些 macOS 核心框架的 DLL。

          1. 没错。我认为这些 DLL 源自 NeXT 的 Openstep for Windows 产品,它可以让你使用 NeXT API 开发 Windows 应用程序。

        2. 在 Windows/Linux 上使用 Xcode 将是非常古怪的,而且不值得为此付出努力–它与 MacOS 的耦合非常紧密,因此在我看来实际上是不可能的。以 MacOS/iOS 为目标的用户通常不会在桌面上运行 Windows。要满足开发人员的需求,更关键的是整个开发人员循环可以在 MacOS 上的 JetBrains 集成开发环境中完成。

          1. > MacOS/iOS 的目标用户通常不会在桌面上运行 Windows。

            如果是这样,他们也会把 MacOS/iOS 作为 “盲目标”,因为这些平台很少经过 QA 或 dogfood。

            > 要满足开发人员的需求,更关键的是整个开发循环都能在 MacOS 上的 JetBrains 集成开发环境中完成。

            我认为目前大多数苹果平台的开发人员都会非常高兴,因为他们可以利用这些工具构建自己的集成开发环境/工具链等,因此 Panic 的 Nova 可以拥有 iOS/acOS/etc 开发插件,或者有人可以将 Sublime Text 变成一个简约的苹果平台集成开发环境。JetBrains 集成开发环境当然拥有广泛的追随者,但在长期使用 Mac 的开发人员中,它们并不像在更大的开发社区中所展示的那样是万能的。

      2. 这样做毫无意义。他们关心的所有开发人员都已经拥有 Mac。如果你使用的是 Windows 或 Linux 系统,并且想要处理 Swift 服务器端代码,那么你可以在自己喜欢的编辑器中使用他们的官方 LSP 或 VSCode 扩展。

      3. 谁会希望 Xcode 是跨平台的?人们在 Mac 上几乎无法忍受它。

        您真正的意思是,人们希望 iOS 开发工具链能够跨平台,而这意味着要将 iOS 移植到 linux/windows 上的管理程序中运行(使模拟器能够工作)。这样的提升太大,没有意义。

        1. 没错。

          我从未在更多地方使用过 Xcode。当我曾经是一名原生移动开发人员时,我希望不必使用 Xcode。

          这在技术上是可行的。但从几年前开始就完全不顺畅了。

    2. 我主要编写 iOS 应用程序已有 15 年之久。大约从 2016 年开始,我就不再需要使用 Xcode 了,因为 Facebook 和谷歌已经拥有基于 VSCode 的全功能编辑器,并可在 Linux 云中进行分布式构建。这非常棒,但我不知道这个系统有开源版本。也就是说,与 Bazel/Buck 集成后,可以在非 Mac 硬件上构建 iOS。

    3. Swift SourceKit LSP + VSCode 现在其实很不错。最近,我在一个 Swift / CMake 项目中将其与 CMake 结合使用,其中唯一的麻烦就是如何正确设置 CMake。其他一切都可以通过 VSCode 的扩展管理器实现。

    4. 在即将到来的 WWDC 上,我对苹果的主要愿望是让 Xcode 不再让我的 M2 变得超级烫手。

    5. 我想要这个已经很多年了。FWIW 我在我的纯 SPM 项目中使用过 CLion 的 Swift 插件,它确实不错。

    6. 我也希望如此!我们现在甚至有了官方的 Kotlin LSP……也许这可以作为灵感来源。

      1. Swift 有一个官方 LSP:https://github.com/swiftlang/sourcekit-lsp

        它于 7 年前首次发布。

        1. 谢谢你告诉我!我完全不知道…

  3. > 我们的 Java 服务面临的挑战之一是,由于 JVM 的开销,它无法快速提供和退出实例。… 为了有效地管理这一点,我们的目标是在需求较低时缩小规模,并在不同地区的需求达到峰值时扩大规模。

    但这似乎是一个完全异步的服务,对延迟的要求非常宽松:

    > 密码监控 “会定期将用户密码与不断更新的、经过整理的已知泄露密码列表进行核对。

    为什么不在后台运行检查?

    1. > “为什么不由后台自行决定进行检查?

      因为当计算完成时,另一方可能没有在监听,而且出于隐私考虑,你不想缓存计算结果。

      事件发生的顺序是

      1. 电话向后台发出请求。2. 手机等待后端的响应。

      1 和 2 之间的间隔时间不能太长,因为手机在等待的过程中一直在消耗电池,所以设备在挂机前的合理等待时间是有限的。

      在隐私敏感度较低的架构中,您可以

      1. 手机向后台发出请求。获取一个令牌,以便稍后进行响应查询。2. 电话稍后使用令牌检查响应。

      但这需要后端保留响应,对于隐私敏感的应用来说,这是你不希望看到的!

      1. 特别是因为请求中包含用户的(散列)密码。你肯定不想在服务器上保留超过必要时间的密码。

      2. 真的有问题吗?客户端可以在请求时传递加密密钥,然后再收集加密结果。只要计算完成且结果加密,服务器就可以忘记密钥,因此缓存不再是隐私问题。

        1. 可以,在计算时间不可避免地很长的情况下,你会这么做。但是,如果你能做一些工作来保证计算速度,那么就能从系统中消除一种潜在的失败模式–一种特别糟糕的失败模式。

          如果你忘记转储密钥(或者删除不干净),那么你就会有一个绝对的隐私漏洞。

          另外值得注意的是,在计算完成之前,你无法转存密钥,因此你需要以某种方式持久保存密钥,这又会带来另一个失败的可能性。同样,如果无法避免,那是一回事,但如果可以避免,你宁可不要密钥持久化。

          1. “UPDATE checks SET result=?

            有那么难吗?

            而且我也不认为持久化每个任务生成的密钥会带来很大的隐私问题。

    2. > 为什么不在后台运行检查?

      可能是需要在计算机处于唤醒和在线状态时进行检查,而且如果密码应用程序最近没有更新,它可能会在启动时刷新数据。

  4. 如果不对 Java 应用程序进行更深入的剖析,很难不认为这整篇文章只是广告内容。与 Swift 相比,Java 的瓶颈或最高 delta 增益究竟在哪里。服务范围看起来非常简单,以前的版本可能存在一些潜在问题,比如代码不能很好地扩展流量的不规则批量性质,或者自定义加密代码不能利用最新的本地 IO 结构。

    我绝不是在为 Java 辩护,很多时候 Java 就像 80 年代的沃尔沃汽车:可靠得令人难以置信,但你要花更多的时间去弄清它的怪声,而不是真正全速驾驶它。

    1. > 如果不对 Java 应用程序进行更深入的剖析,就很难不认为这整篇文章只是广告内容。

      如果苹果公司写的任何东西都能让你满意,我会感到很惊讶。TFA 明确指出,他们首先在 Java 的 GC 下尽可能优化了 Java 版本,一旦明确有必要重写,他们评估了几种语言(不仅仅是 Swift),他们 “在整个开发和部署过程中对性能进行了基准测试”,并分享了之前/之后的基准测试结果。

      1. 好吧,我很怀疑他们是否真的尽其所能进行了优化。事实上,从字里行间读来,他们几乎没有做任何尝试。

        例如,他们提到 G1GC 比原来的更好,但还不够好。然而,他们提到的 GC 停顿时间过长等问题表明,G1GC 并不适合他们。相反,他们应该使用 ZGC。

        把 G1GC 称作 “新 ”也很奇怪,因为它是在 2016 年发布的 Java 9 中添加到 JVM 中的。也就是说,他们把一个 9 年前的收集器说成是全新的。难道他们刚刚更新到 Java 11?

        如果他们是在抱怨启动时间,那为什么没有提到 AppCDS 的使用?或者更极端的 CRaC?用 Graal 进行 AOT 编译呢?

        他们唯一提到的是垃圾收集器,而这只是 JVM 的一个方面。

        而且,JVM 在各个版本的启动时间和 GC 性能上都取得了巨大进步。从 11 版到 17 版,再从 17 版到 21 版,JVM 在性能上都取得了相当大的进步。

        我很抱歉,但这真的像是苹果营销人员在找理由吹捧 swift 超级棒。

        1. 作为一个没有专业使用过 Java 的人,这是很有帮助的怀疑论。谢谢!

          > 他们刚刚更新到 Java 11 吗?

          作为一个将支持 “延长 ”至 2032 年的 LTS 版本,这当然是可能的。

          做出这一决定的另一个近乎肯定的因素是,苹果对关键的外部依赖性有着极端、创伤性的憎恶。11 LTS 的 “首要 ”支持已于去年秋天结束,这让我不禁怀疑,做出这一选择的主要原因是:究竟是(1)花时间评估甲骨文随后发布的 Java LTS 版本是否能解决他们的性能问题,还是(2)利用这段时间将 Swift(一种自创的 “更开放 ”的语言,他们比世界上任何人都更了解它)应用到苹果规模的实际问题中,以最终取代所有基于 Java 的后端为目标,这样做会更好。

          1. 虽然它受到支持(接收安全更新),但这并不意味着它仍然是一个古老而过时的运行时。Java 11 发布已近 8 年。与最新的 JDK24 相比,它在提交和性能改进方面落后了数千次。

            1. JDK 24 并非 LTS 版本,第一方支持将于 9 月份结束。它也比 Java 11 新 6 年半。

              我想很多公司都不会使用比 JDK 21(最新的 LTS 版本)更新的版本。

              1. 我不明白你的意思。

                JDK 11 LTS 是 2018 年发布的,之后甲骨文推送了两个 LTS 版本: JDK 17 发布于 2021 年,JDK 21 发布于 2023 年。除此之外,甲骨文还承诺每两年发布一个 LTS 版本,下一个版本计划在今年晚些时候发布。

                使用 LTS 并不意味着您必须在最旧的可用版本上创建应用程序,而是意味着如果您以最新的 LTS 版本为目标,您的应用程序将在很长一段时间内拥有可预测和受支持的运行时。

                如果他们不得不在 2024 年启动 Java 11 项目,这只能说明一个比 GC 更深层次的组织问题。

      2. > TFA 明确指出,他们首先在 Java 的 GC 下尽可能优化了 Java 版本

        不,没有。

  5. 我知道这篇文章可能有些偏颇,但对于一家为云计算/内存使用付费的公司来说,资源使用的改善是难以忽视的。

    我要研究一下服务器端 Swift。

    看来要找到适合在 linux 上开发的非 xcode 工具方法,还需要一些摸索。

    相比 VSCode,我更喜欢 Jetbrains 工具,如果有人在这方面有什么建议的话。

    1. 我不认为 Swift 有什么特别神奇的地方,它只是在没有 JVM 庞大运行时的情况下运行的不同之处,以及内存管理的优势。Go 可能会有所改进(而且很可能更容易从 JVM 语言进行心理调整),而 Rust,一旦你从心理上适应了它的模型,将会有更大的改进。Swift 具有面向对象的优势(如果这在你心目中是优势的话),但我在 10 年前就认为,随着向微服务的转变,Java/Spring 应用程序在云/微服务模式所需的快速启动/关闭方面将不再那么好用。

      1. 在这种情况下,Rust 真的会比 Swift 更好吗?这不或多或少取决于 Rust 中使用的是哪种内存管理方式吗?

        1. Rust 和 Swift 的内存管理策略类似。Swift 中对性能影响最大的是方法调度,因为它遵循 Objective C 的策略,这将导致对象方法的间接调用。这在 Rust 中是可能的(使用 Box(dyn Trait)),但在关键路径中不鼓励使用,而是通过枚举进行静态调度,或通过 Rust 泛型进行重定义调用。当然,Swift 也有类似的功能,但对于这两种语言,要想获得最佳性能,就必须在开发过程中有意识地做出选择。

          1. > Swift在方法调度方面的最大性能损失是遵循 Objective C 的策略,这将导致对象方法的间接调用。

            虽然 Swift 可以使用 Objective-C 的消息发送功能与 Objective-C 库进行通信,但这并不是它的主要调度机制。就文章中描述的服务而言,它甚至不可用(因为它运行在 Linux 上,而 Linux 没有 Objective-C 运行时实现)。

            相反,与 Rust 一样,Swift 的主要调度默认为静态调度(直接在类型上调度,或通过重化泛型调度),也可以通过 any 进行动态调度(类似于 Rust 的 dyn)。在使用子类化时,Swift 也有基于 vtable 的调度,但这同样是选择性的,就像 any/dyn 一样。

          2. 除了 Airspeedswift 的评论之外,在 iOS 应用程序之外,Swift 中根本不需要使用动态派发。非官方应用程序会有很多内部包/目标,这些包/目标甚至不导入任何基于 Objective-C 的库,只需使用 swift 工具链即可编译和运行。您甚至可以内联所有常用函数调用。Idiomatic Swift 还很少使用类,大多数类最好都声明为最终类。

    2. 遗憾的是,Jetbrains 不再销售 AppCode,也不再支持他们为 CLion 开发的 Swift 插件。我希望他们能开源这些插件,因为 CLion 远远优于 Xcode。不过现在,我们真的只能使用 Xcode(Mac)或 VSCode(无论在哪里)了。尽管如此,我真的开始喜欢上使用 Vapor 的服务器端 Swift。Swift 作为一门语言,非常适合开发。

    3. 如果资源使用率的提高完全是由于偏见造成的,那么它应该很容易被忽略?

  6. 我想知道 Apple 是如何对 Linux 上的 swift 应用程序进行生产监控、可观察性和性能剖析的。根据我的经验,这是 Swift 服务器生态系统中缺失的关键部分之一。

    您可以针对 jemalloc 进行链接,也可以使用 google perftools 来获取堆和 CPU 配置文件,但要很好地利用它们是很有挑战性的,尤其是在 Swift 方法混杂和激进内联的情况下。

  7. 我一直有点纳闷,为什么大型企业(它们有足够的资源聘请专家)不聘请精通 Rust 或 Elixir/Phoenix 等技术的人?

    说我们想雇佣 Java 或 C# 等常用开发人员是一回事,但如果你有长期计划和执行战略,为什么不选择可能带来更大回报的技术呢?

    ITT:我明白他们为什么选择 Swift,这是苹果自己的内部技术。这完全说得通,我一点也不反对。写得不错。

    1. 这是因为 Java 和 c# 已经非常商品化了,我们不需要付给员工那么多工资。

      另外,在中小企业和小型SaaS领域,短期的资产负债表与长期的产品管理无关。我认为,除了开发人员,其他人根本不在乎。

    2. 他们确实有Elixir职位,如https://jobs.apple.com/en-us/details/200562288/senior-softwa…

    3. 原因很多:

      世界上没有足够多的 Rust 专家供一般企业聘用并从中受益。

      Elixir/Phoenix 与 Rust 相比,与 Java 相比并没有数量级的改进,只是边际改进。企业对此并不在意。

    4. 听起来你是在问为什么企业不选择写 Rust 代码而写 Java 代码。我不会因为开发者有 Elixir 的经验就将其拒之门外。

      这实际上取决于是否有人能证明某个应用程序/子系统有专门的需求,需要聘请专家,以及他们是否能成功证明该系统应该使用需要额外培训并带来额外项目风险的技术。

      在您处理的不是企业应用程序而是实际服务之前,甚至连维持开发团队进行维护都很困难–如果您的一名 Ruby 开发人员离职,可能就没有人能够维持应用程序的运行了。

      即使是在开发服务的过程中,如果服务是单体的,我们也会强烈建议你坚持使用单一的技术栈。

      1. 不,我想说的是,如果目标是降低资源使用率、提高吞吐量、并发性、速度/性能等,那么大公司就可以利用 rust 或 elixir 等技术实现这种 “不公平的优势”,因为与中小企业或初创公司相比,它们拥有足够的资源。

        当然,每家公司和每个组织都必须考虑什么对他们来说是最好的和可行的。毫无疑问,你提出的观点很有价值。

  8. 非常有趣。我希望他们能更详细地介绍所涉及的其他技术。

    Java 服务是使用 Spring(boot)吗?

    还考虑了哪些其他技术?

    我认为 Go 也是其中之一。是 Go 的类型系统过于简单,还是其他因素?

    1. Swift 是苹果自己的语言。他们拥有从最底层到最高层的所有专家。

      为了对竞争技术进行公平的技术评估而撰写冗长的报告/文章完全是浪费时间,而且如果答案还是 Swift,也不会有人相信。

      > 我认为 Go 也在其中。…

      我认为根本没有理由对 Go 进行评估。

        1. 但这忽略了一个事实,那就是苹果在 Swift 上投入了巨资。

          我认为他们已经在某些地方使用 Go,但他们已经明确表示要在合理的情况下尽可能多地使用 Swift。

          我怀疑他们没有评估 C++、Rust、Go、Erlang、Node 和其他 12 种东西。

          他们有其他 Swift 服务的经验,知道 Swift 会有很好的表现。他们的员工已经了解并使用 Swift。

          如果 Swift(和使用的库)不够好,他们会让员工改进它,然后等着放弃 Java。

          如果你去 Java 商店,说你想用 C# 来做 Java 能做的事情,他们可能会说用 Java 吧。

          我不认为这篇文章是在说 “Swift 是最好的东西”,而只是在说 “嘿,Swift 在你意想不到的地方也能发挥巨大作用,这是你可能不知道的一种选择”。

          1. 微软在 C# 上投入了大量资金,但他们仍然评估(并选择)了 golang。

            1. 对于 TypeScript 的编译器来说,是的。我能看到一些真正的好处,比如 Go 已经在一些他们希望与非微软人员合作的开源软件中很常见。我认为 C# 在这方面的应用要少得多,而且在追求纯粹性能时,我认为像 C# 这样的字节码语言不会有同样大的收益。

              我不在 .NET 生态系统中,所以我不知道本地 AOT 编译成机器码是否是一种选择。

              但无论如何,在这种情况下,苹果是在为自己提供内部服务。我认为,如果 MS 选择重写某些 Windows 服务的服务器后端,这将是一个更好的比较。他们会选择 Go 吗?

              我不知道。

              1. 原生 AOT 如今已经相当不错了,我认为还有其他政治因素在起作用。

                Azure 团队使用 AI 从 C++ 转换到 Rust 没有问题,参见 RustNation UK 2025会谈。

                此外,他们还提到了移植而非重写的原因,但由于 Go 的类型系统较弱,他们不得不重写整个 AST 数据结构。

                最后,支持 Blazor 的 WebAssembly 工具比 Go 成熟得多。

              2. 真正的问题不在于他们是否会选择 Blazor,而在于他们是否愿意对其进行评估。鉴于他们过去的行为,正如我上面提到的,他们似乎愿意评估各种选项,并选择最适合的工具。

                1. 现在他们的态度确实开放得多。我还记得以前,微软服务器上只有微软工具和微软语言,否则什么都没有。

                  他们绝对不会碰 Go。

              3. 你刚才说苹果选择 Swift 是因为大量投资。微软在 C# 上的投资要大得多、多得多,但你却找到了所有理由来证明你最初的论点是无效的。

                这篇文章只是一个团队为了宣传而做的营销,并没有什么深意或更大的苹果计划。

        2. 我不相信这个理由。

          首先,微软错失了另一个让人们学习 C# 的机会。

          其次,在 BUILD 会议上,Anders 最后解释说,鉴于 Go 类型系统远不如 Typescript,他们无论如何都需要重写 AST 数据结构。

          与 Blazor 工具链相比,Go 在 WebAssembly 上的表现相当糟糕,他们希望谷歌能做出必要的改进,这是 TypeScript playground 和在浏览器上运行 VSCode 所必需的。

          最后,参与这项工作的一些关键开发人员在最新一轮中被解雇了。

        3. 在我看来,这仍然是一个长期的错误,是进化的死胡同。

          1. 这重要吗?今天,他们通过转换获得了 10 倍的进步。任务完成。

            X 年后,另一种语言会出现,那时他们就可以改用这种语言,不管它有什么好处。这就是技术的本质。

            1. 限制可能比这更快。由于围棋中不可避免的高代价抽象,他们现在的处境是无法再有大的改进。如果他们选择了更低级的东西,那么在第一次转换之后就会有更多可能。

              1. 我的错,我不应该在这里写上数字,因为这正是你所关注的。

                用汇编语言重写是个好办法,但这样做会有其他代价。

                1. 我没有关注数字,我只是指出 Go 的优化潜力低于其他选项。

                  当然,这也是一种权衡,他们的理由也不错,但重写既昂贵又具有破坏性。如果是我,我就会选择能避免日后二次重写的方案。

                    1. 我很清楚他们是怎么做的。从主要是自动化的重写开始,也就是他们令人困惑的所谓 “移植”,是有道理的。

                      但在这一步之后,最终结果将由人工进行维护和更改。以这种方式进行改进(包括性能改进)是完全合理的。我所质疑的只是目标的选择,因为它排除了一些未来可能的改进。如果你正在编写(无论是否半自动化),这也是一个面向未来的机会。

                      我不明白你为什么要对单纯的技术分歧如此对抗。

                    2. 我并没有不同意你的观点,我上面的评论被标记是很奇怪的,因为我并没有攻击你。¯_(ツ)_/¯

                    3. 我不知道,我没有标记它。

                      我不同意 MS 的选择,而你似乎不同意,甚至声称我没有读过他们的改写计划和理由。

                      这并不重要。

              2. 仅供参考:我与这场斗争无关。

                 > 围棋中不可避免的代价高昂的抽象
                

                你能分享一些吗?

                1. 隐式结构副本、垃圾回收、接口分派等。

          2. 绝对是这样。只需环顾一下其他语言的生态系统和 JS 本身即可。

            Rust 是一种优秀的语言,适合嵌入其他语言并作为开发者工具的底层。

            也就是说,总有一天,新的 typescript 二进制文件会编译成 WebAssembly,反正这也没多大关系。

            1. 是的,有一种相反的方法。给 TypeScript 添加底层控制,让它编译到 WebAssembly,那么编译器本身也会很快。

              不过,我怀疑他们更想要的是编译器的速度,而不是 WASM 目标。

        4. 是啊,他们还可以向微软学习如何为 ARM 架构编写操作系统。

  9. 我要打电话了: 除了苹果,Swift 在后端对所有人来说都毫无意义,试图让它作为后端服务语言起飞,就像移植 Xcode 跨平台并试图吸引非苹果开发人员使用它而不是 VSCode、任何 JetBrains IDE 或 Visual Studio 一样毫无意义。

    市场上已有的选择实在是太多了,而且现有的工具在特性、功能和能力上已经远远超过了苹果所能提供的任何东西。有趣的是,他们其实有钱在这个领域投入资源,与 C#、Java、go 或 Rust 竞争,但他们不打算这么做,因为这实在是离他们的核心业务太远了。任何用 Swift 编写的后端服务都不会在云端的 Mac 上运行,也可能不会只为 iPhone/iPad 客户端服务,所以当我们知道苹果领导层会将其视为事后考虑时,又何必费心呢。

    如果它真的起飞了,我敢打赌,那一定是因为开源社区提供了解决方案,而不是苹果公司,即便如此,它也将是一个很小的利基市场。事实上,整个项目是由 Vapor 支持的,这是一个开源 Swift 项目,我猜测团队之所以选择它,是因为 Vapor 作为一个项目最终达到了他们想要的成熟度。苹果并没有像微软的 C# 和 ASP.NET 那样,自己用 Swift 构建自己的网络框架。所有这些都让我对 Swift 的后端功能更加怀疑。除了将 Swift 移植到 linux 等基础工作外,苹果不会在后端领域为 Swift 做任何特别的事情,但会利用其他人构建的开源内容。

    1. 苹果当然有自己用 Swift 编写的网络框架。

      不,我不知道为什么它们没有公开(至少现在还没有)。但我知道它们为许多面向公众的服务提供了支持。

    2. > 他们不会这样做,因为这离他们的核心业务太远了

      苹果汽车更远吗?

    3. 我真的很好奇 Hacker News 上的人们对 Swift 的看法。感觉五年前我就听说过 Swift。人们似乎很喜欢 Go,Rust 也很酷(我学过那个),而 Python、C#、Java 似乎还在这里。

      我的意思是,我问的是通用语言,而不仅仅是后端语言。

      1. Swift 确实让人兴奋不已,但苹果公司决定不利用它,炒作也就随之偃旗息鼓了。Swift 几乎就是 Mac/iOS 语言,而且没有迹象表明它会很快改变。

      2. Rust 和 Swift 共享很多核心概念。

        Swift 有一些额外的部分是为了兼容 Objective-C(在苹果平台上运行时),但除此之外,最大的区别在于语言本身的设计和人机工程学。

        如果我需要完全控制内存(比如网络服务器),或者要编写在嵌入式设备上运行的代码(比如不使用 Linux),我会使用 Rust,即使 Swift 在技术上也能满足我的需求。

        如果我创建的是移动或桌面应用程序,情况则恰恰相反。对于本文中的网络服务,我可能更倾向于两者都不使用,但如果选择有限,我可能还是会选择 Swift。

      3. 我非常喜欢它。它给我的感觉是简洁易读,同时拥有出色的异步和其他现代特性。有点像编译后的 TypeScript,没有 JS 带来的所有包袱。

        它也有一些问题,主要是编译器,但我喜欢用它来开发。

        我怀疑你较少听到它,是因为它不再是新的东西,开源社区似乎也不太关心它,这一点与 Rust 不同。

        它似乎仍被视为 “iOS 语言”,尽管它能做的远不止于此,而且还能在其他平台上使用。

      4. 对于苹果生态系统中的任何人来说,这都是一门很好的语言。

        如果一个人宁愿与操作系统无关,那就不太适合了。

      5. 至于 HN,我看到有评论说 swift 变得复杂臃肿,有很多方法可以做同样的事情。就像 C++ 一样。

  10. 我很想看到微软关于 C# 的这样一篇文章。“我们研究了一些替代方案,最终选择了我们自己的语言,它符合任务要求,运行良好,在技术、开发和可维护性方面都是最佳选择。

    读得很好,谢谢你的分享!在我看来,这意味着你很成熟,你分享了一些东西,而不是从许多公司都存在的基本东西中制造出晦涩难懂的秘密 <3

      1. 不完全一样,但很接近。我猜 OP 提到的是从一个堆栈迁移到一个完全不同的堆栈。

  11. 老实说,我非常怀疑苹果公司是否真的竭尽全力使 Java 启动快速,并使 GC 在负载情况下表现良好。

    G1GC 是一个很好的收集器,但如果暂停时间真的很重要,他们应该使用 ZGC。

    如果启动是个问题,最近几个版本的 Java 引入了 AppCDS,它在各个版本中的表现都相当不错。

    如果这还不够好的话,Graal 很早就提供了 AOT 编译,既能快速启动,又能降低内存使用率。

    要将这些功能添加到构建管道或部署中并不难,只需要 Apple 使用最新版本的 Java 即可。

  12. ARC 赢了吗?考虑到他们对 G1 所做的调整,对 GC 有更深入了解的人能否解释一下为什么会这样?这是特定工作负载的优势,还是普遍适用?

    1. 虽然已经过去很久了,但我曾经在 GC 工作过。我猜是内存占用(以及高速缓存本地性的损失)造成的。复制或标记/扫描可以很快,但前提是你必须给它们提供大量额外内存,以便在两次 GC 通过之间积累垃圾。ARC 一直在做一些额外的 CPU 工作,但它有很好的局部性,并不需要额外的内存。

    2. 编写性能出色的 Swift 的方法是无类,因此不需要 ARC,但在很多领域都需要类。最近,Swift 在利用很多类似 Rust 的所有权特性,让它可以在没有类的情况下做更多事情,我猜苹果团队会使用这些

      1. 假设你说的是纯 Swift 而不是 iOS,那么类在哪些领域是必要的?

        1. 复制成本较高的地方(大多数 Swift 集合都由类支持 COW 语义)。需要位置稳定性的地方(需要互斥)。资源分配。这些就是不可复制类型要解决的主要问题。

          1. 是的,很好的例子,谢谢你的解释。

  13. 听说像苹果这样的公司在服务器端使用 swift,这改变了我对服务器 Swift 的看法。

    我一定会再看看的,很高兴看到它变得足够成熟,成为另一种可行的选择

    1. 最重要的问题是:软件包管理、社区、分叉、打补丁的便利性以及其他与依赖性管理相关的问题。服务器端开发需要对这些问题有很好的回答。

      1. Swift 已经回答了所有这些问题。使用 SwiftPM 的非 Xcode swift 非常可靠

        1. 软件包注册表在哪里?(crates.io 模拟)找不到一个

  14. “更快的启动时间是支持这种动态扩展策略的关键要求”。

    十年来,Google AppEngine 一直成功地做到了这一点。这并不容易,但却是可能的。

  15. > 该功能有一个服务器组件,运行在基于 Linux 的基础架构上,由苹果公司维护。

    苹果公司不在内部 Xserve 类似设备上的 XNU 上运行他们的服务(或与旭日合作或为旭日做贡献,让 Linux 在所有 Mx CPU 上都能很好地运行),这让我感到有些惊讶。

    1U Mac Studio 将是杀手级产品。鉴于他们已经完成了 Studio 的大部分工作,我甚至怀疑这是否会是一项巨大的工程。

    1. 众所周知,他们使用 Azure(我猜还有其他供应商)的云服务。

      如果他们要在公共云和预置云中运行,Linux 是合理的。如果要使用 Linux,目前使用 x86-64 也很合理。

      正如你提到的,他们必须为 Asahi 做贡献,这将占用资源。即使忽略这一点,苹果硬件在服务器工作负载上的性价比可能也不值得。

      即使稍微好一点(他们不支付零售价),但与他们在 Azure 中运行的设置不同,再加上与普通 1U PC 相比的特殊机架工作等,可能意味着根本不值得。

    1. 它运行在基于 Linux 的基础架构上。我们已经更新了博文来说明这一点。谢谢!

    2. 众所周知,苹果是 RHEL 的大客户,包括 Azure 上的 Linux。

      可以肯定的是,iTunes 商店、其网络商店等也都是基于企业级 Linux 构建的。

      这并没有错。使用最合适的工具。大多数车主都没有检查过发动机舱。

      1. 我不认为很多 Azure 服务是在 hyper-v 上运行 Linux 的,对吗?Azure(据我所知)在裸机 Linux 上的应用相当多。

        1. 他们的许多 SaaS 产品是,但许多基础架构产品下面运行的是 Windows Server。租用任何 Azure 虚拟机,无论客户操作系统如何,下面都使用 Hyper-v 作为管理程序。

    3. 在这种情况下可能是 Linux,但苹果也使用基于 M 系列的定制服务器,运行加固的基于达尔文的操作系统,用于用户数据的大语言模型(LLM)处理。

      1. 我非常非常想了解一下定制的 M 系列硬件。目前还没有多少消息流出。

      2. 我甚至都不确定这些硬件是否已经开启。

      1. 众所周知,苹果公司在服务器上使用 Linux,但我认为 BSD 也有可能。

        macOS 的用户界面基于 BSD,所以你会在这里找到很好的契合点。而且,一些常见的 BSD 并不擅长服务器的工作。我知道它能做很多事。

        谁知道是否有人讨论过这个问题呢?他们不会要 Windows(许可、光学等),而且 macOS 也不是为了做高性能服务器而调整的。Linux 的性能令人难以置信,而且无处不在,是非常非常安全的选择。

        1. 苹果曾经使用过的另一种 BSD 是 NetBSD,在 AirPort 无线路由器停产之前,他们就是使用的 NetBSD。

  16. 我想试试服务器端的 Swift,但当最好的工具都绑定在一个平台上时就很难了。

    1. 如果您指的是拥有 “最佳工具 ”的 Xcode,那我就不同意了。我每天花 8 小时使用 Xcode,发现 VSCode 往往更好用。我只是想在 Linux 上试试。

    2. 对于使用 Swift 进行通用编程而言,带有官方 Swift 扩展的 Cursor 要优于 Xcode(即使在 macOS 上也是如此)。

  17. 很高兴看到使用 Vapor 的成功案例,而且苹果自己也在使用 Vapor。Vapor 的灵感来源于 Laravel,作为 Laravel 的长期用户,这让我看到了 Vapor 的希望。

    Swift 是一门可爱的语言,直到最近它应该更名为 Swift++。

  18. 这看起来很酷,只是我看到他们在堆栈中使用了 Cassandra。我使用的是旧版本的 Cassandra,发现它是管理的噩梦。

  19. 我去年做了一些 iOS 开发。我不喜欢其中的 iOS 部分,但 swift 本身感觉不错。

    swift 是网络版的吗?

  20. 对苹果的憎恨程度令人咋舌。如果把 swift 换成 Rust,它的投票数将是现在的 10 倍,而且只有正面的炒作。

    1. 现在,每个人和他们的家人都知道,只要在标题中加入 Rust,就能获得大量更新。事实就是如此。

  21. >Java 的 G1 垃圾收集器 (GC) 缓解了早期收集器的一些局限性

    自 JDK 6 G1GC 以来的……现有和默认 GC?

    >由于高负载下 GC 停顿时间过长、性能开销增加以及针对不同工作负载进行微调的复杂性等问题,大规模管理垃圾回收仍然是一项挑战。

    要是我们能发明其他垃圾回收器就好了,比如从 JDK15 开始的 ZGC (https://openjdk.org/jeps/377),甚至是一直回溯到 JDK8 的 Shenandoah (https://wiki.openjdk.org/display/shenandoah/Main),这些垃圾回收器的目标是实现亚毫秒级的 GC 停顿,并能以令人难以置信的速度扩展到甚至 TB 级的 RAM。无需对 GC 进行调整。

    > 由于 JVM 的开销,无法快速配置和停用实例

    如果我们发明了 Java 的 AOT 编译,甚至是本地编译,那该有多好。我们可以称之为 GraalVM 或其他什么 (https://www.graalvm.org/)

    >在 Java 中,我们严重依赖继承,这会导致复杂的类层次结构和紧密耦合。

    要是能像使用协议一样使用接口就好了。想象一下,即使使用像 Kotlin 这样提供接口委托的 JVM 语言也是如此!我想我们不得不继续自寻烦恼了。

    >Swift的可选类型和安全解包机制消除了到处进行空检查的需要,降低了空指针异常的风险,提高了代码的可读性。

    这个我同意。不过,要是有 NullAway 就好了。

    >Swift的异步/等待支持是一个很好的补充,它简化了我们处理异步任务的方式。

    撇开 Swift 基于 MainActor 的整个 async 故事太烂不谈,我很喜欢用 Rust 和 tokio 写 async,Swift 6 也是让人头疼的原因,因为他们关于 async 的指南一直都很糟糕: 天啊,要是 JDK 中包含虚拟线程之类的东西就好了,这样写起异步代码来就像写同步代码一样,只需要一个小小的封装。我们可以把这种收集了许多线程的东西叫做… 织布机!(https://openjdk.org/projects/loom/)

    >总的来说,我们使用 Swift 的体验非常好,我们完成重写的速度比最初预计的要快得多。

    你们使用完全由自己控制的语言和库重写了一个已有文档的现有服务,而且速度很快?哇

    >除了出色的支持系统和工具之外,Swift 本身对模块化和可扩展性的强调也是重要原因。

    在称 SPM 为 “优秀的工具 ”之前,我宁愿用 Ant 脚本重写我所有的构建脚本,手动调用 `make`,不过没关系。

    总之,很抱歉我的讽刺,但这只是苹果公司为其 Swift 语言做的广告。编写低分配的 Java 代码是可能的,而编写高效的竞技场是不可能的…… Java 的 GC 世代就是竞技场。同样,是的,它的性能更高。也许是因为他们的间接性太强、继承滥用导致到处都在追逐指针,而在 Swift 中没有这样的机会意味着他们不能浪费性能?阻碍性能提升的大部分原因是编码标准和编写时的坏习惯,在那个黑暗的年代,“四人帮 ”已经深入每个程序员的心中。为每个端点添加一些反射功能,是因为当时的 Java 出于某种原因非常喜欢这种功能(主要是因为编写源代码生成任务或编译器插件在当时绝对是地狱般的工作,而现在则是 “我的工作”)。如果运气好,任何网络序列化也使用了反射(感谢 GSON 和 Jackson),你就会知道吞吐量去哪儿了。

    他们有极其冗长的现有 Java 8 代码,只是决定使用 Swift 重写它们,因为这就是苹果公司现在的大部分工作。这篇文章中的任何概述都只是事后的合理化解释。如果失败了,这篇文章也就不会出现了。现代 Java 虽然在某些方面仍然有些粗糙(我完全理解对语言的偏好,我更愿意使用我喜欢的语言),但它可以而且绝对会在各个方面与 Swift 竞争。这只需要改掉在 Swift 中编写代码的坏习惯。

    另外,Java 从未告诉过我它搞不清楚我的 30 个链式收集器调用的类型,所以也许 Hindley-Milner 并不适合我。

    1. 苹果不会使用和推广 Swift,谁会呢?他们肯定不能指望你来扮演这个角色。

      1. 你可以使用和推广 Swift,而不必虚情假意。

        Swift 有一些很好的特性,而且几乎是一种非常讨人喜欢的系统语言,这主要归功于苹果公司 “我们需要为 iOS 应用程序提供这种功能”。

        一篇文章仅仅提供了一些无法证实的说法,就说 Swift 对他们有多好,(这些说法代表了地球上关于 Swift 的大部分最佳知识)就像人工智能生成的垃圾邮件网站一样有用。任何通过这篇文章来决定是否在后端使用 Swift 的人都是小丑。

    2. 有趣的是,他们使用 Swift 6 的可能性可能为零,因为在没有发布 Swift 6 之前,你知道,他们不可能真正使用过这门语言。

  22. 绝对是胡说八道。

    这属于 “我们重写了那些不知道自己在做什么的人写的东西,而且效果更好 ”的范畴。

    庞大的类层次结构(自 1990 年以来,我们就更倾向于组合而非继承!)、拙劣的异步代码(由于虚拟线程的存在,Java 中甚至不需要异步代码)、糟糕的启动时间(可能是由于 Spring 的存在)、巨大的堆大小(可能是内存泄漏或其他拙劣代码,再加上由于路由和糟糕的启动时间而无法重启)。

    哈欠。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注