IntelliJ IDEA News

IntelliJ IDEA 中更快的代码可交互时间

Read this post in other languages:

IntelliJ IDEA 功能强、范围广,因此对资源有一定需求。 根据您正在处理的项目,IDE 可能会出现滞后,这自然会令人沮丧。

打开项目时也许是开发者需要等待的最常见场景。 IntelliJ IDEA 需要加载和同步项目、执行索引编制以及完成许多其他小任务才能启用所有实用功能。

在这篇博文中,我们将介绍在新版本 IntelliJ IDEA 中为提高性能而采取的措施,这些措施缩短了代码可交互时间并使 IDE 从启动开始就具有更高的响应速度。

我们的使命:改进代码可交互时间

对于 2023.2 之前的 IntelliJ IDEA 版本,IDE 必须等待项目的 Maven 或 Gradle 项目模型完全同步后才能开始编制索引。 然后,在等待索引编制完成时,IDE 的所有智能功能都被禁用,包括代码高亮显示和导航。 只有在索引编制完成后才能使用它们。

下面是相关组件的示意图:

项目越大,同步项目和编制项目索引所需的时间越长。 虽然这在意料之中,因为大型项目对于 IDE 来说更加复杂,但等待几分钟才能开始工作仍然有些糟糕。

然而,由于加载项目时要执行的步骤太多,即使是较小的步骤也会花费大量时间,让人感觉 IntelliJ IDEA 运行缓慢。

没人喜欢等待,尤其是您想要投入工作的时候。 因此,我们将改善这种状况作为一项高度优先的任务。

为了衡量我们的进度,我们决定跟踪我们所谓的“代码可交互时间”– 从应用程序启动或项目打开到可以在其中正常处理代码的时间。 我们的目标是尽可能缩短代码可交互时间。

改进项目打开流和体验

在 IntelliJ IDEA 中改进启动和项目打开的问题实际上非常复杂,因为它取决于多个组件及其互连。 不过,这种复杂性也有好处,因为它可以让我们从多个角度解决问题。 在等待技术改进方面的长期工作取得成果的同时,我们还调整了 IntelliJ IDEA 的索引编制方式,用户已经可以体验到在代码可交互时间方面的显著改进。

技术改进

缩短代码可交互时间的一个明显方式是执行技术更新以提高 IDE 的性能 – 优化代码和架构、使用更好的硬件、并行化等。 IntelliJ IDEA 已有 20 多年的历史,早期的一些架构和算法决策仍然存在于产品中。 

这方面的工作正在开展。 我们投入了大量精力来适当监测、调查和优化性能瓶颈,并且已经取得了一些显著成果。 我们将应用程序的启动应用程序性能指数 (Apdex) 提升到顶级类别,得分为 0.94,将多线程索引编制的速度提高了 25%,并消除了并行索引编制过程中不必要的锁,减少了其他线程等待此类锁的时间。 但这将是一个漫长的过程,因为重构可能会对 IDE 中的其他子系统产生影响,需要经过较长时间的仔细评估。 有关技术性能改进的更多详细信息,请观看 Yuri Artamonov 的精彩演讲,并继续关注更多文章。

在技术层面开展工作的同时,我们还决定另辟蹊径来解决 IDE 的感知性能问题。 

分阶段同步索引编制

IDE 不一定需要技术改进,用户就能体验到它的速度提升。 只要能够更快开始工作,他们就会感受到性能改进。 通过研究,我们了解到许多用户认为,当他们能够看到项目结构和正确的代码高亮显示时,IDE 就可以开始用于工作了。 所以,这就是我们努力的重点。

IDE 必须执行几个关键步骤才能使高亮显示和导航正常运作,但我们想知道这些步骤是否真的需要按顺序依次执行。

2023.3 版本中一些很有前景的实验表明,将同步和索引编制过程分为几个阶段并以异步方式运行,可以让用户更快地开始与代码交互。

因此,作为第一步,我们让 IntelliJ IDEA 在实际从 Gradle 或 Maven 等底层构建工具获取项目模型之前开始对项目目录中的文件编制索引。 这样做的缺点是,不必要的文件也被编入索引,并且与构建工具同步后,需要重新编制索引。 不过,根据我们的测试套件,整体代码可交互时间(包括同步和完整索引编制)显著缩短,在大型项目中的速度提高了 1.5 倍。

但是,如果不加载项目模型,就无法正确建立项目各部分之间的关​​系、显示正确的项目树、高亮显示或提供导航。

为了解决这个问题,我们实现了所谓的分阶段同步。 我们让 IDE 分阶段获取模型,而不是一次性从构建工具请求完整项目模型。 目前有两个阶段。

阶段 1:跳过依赖项解析

在第一阶段,即项目加载过程的早期阶段,IntelliJ IDEA 不会解析依赖项或连接到互联网。 它只是提供一个足够精确的模型,让 IDE 能够显示项目树、对项目中最必要的部分编制索引,并提供一些必要的智能功能。 

显然,这个阶段之后一些依赖项可能仍然缺失,从而导致解析问题,甚至出现代码即使正确也被标记为红色的情况。 IDE 实际上可以感知这些误报错误,并通过抑制因缺少依赖项而导致的错误在个别语言支持级别解决这些问题。 它还能正确处理带有相应消息的导航尝试。 自 2024.2 版本起,此错误禁止适用于 Java,在 2024.3 版本中,支持已扩展到 Kotlin。

Maven 中第一阶段尤其快速,因为它的静态 pom.xml 配置文件可以由 IDE 解析而无需启动 Maven,同时还能提供足够的知识来构建非常精确的模型。

对于本质上动态且脚本非常灵活的 Gradle,IntelliJ IDEA 目前无法独立解析脚本,这意味着它必须运行 Gradle 守护进程。 通过仅向 Gradle 请求 sourceSets、必需语言级别和其他基本信息,我们加快了这一过程。 不过,通过声明式 Gradle 计划,我们将来也许能够带来大幅改善。

阶段 2:下载并解析依赖项

在第二阶段,IntelliJ IDEA 下载所有插件和依赖项,正确解析所有配置,并为 IDE 提供完全准确的模型。 然后,索引根据完整模型更新。

通过这种两阶段方式,在依赖项下载和解析的同时,您可以更快获得几乎功能齐全的 IntelliJ IDEA 版本。

作为一项额外改进,我们使许多功能在索引尚未就绪时也能运行,进一步缩短了代码可交互时间。 最重要的是个别文件中的代码高亮显示、部分代码解析和运行配置。 当然,准备好底层索引会让这些操作更快,但即使只有部分索引,它们也能可靠地工作。

结果

总体来看,整个流程现在是这样的: 

我们怎么知道是否值得?

根据项目,我们测试套件中的代码可交互时间(或者更准确地说,以上架构中完全高亮显示之前的时间)在第一次打开项目时速度最多能快上几倍。

下面的示例展示了项目树的显示速度和项目中高亮显示的启用速度有多快,以前访问这些功能需要几十秒的时间。

调查显示,大约 30% 的用户认为 IntelliJ IDEA 2024.2 让他们能够更快开始编码。

后续计划

虽然并非所有 IntelliJ IDEA 功能都能在编制项目索引时使用,但两阶段同步方式无疑加快了整体启动性能,让您更快地开始与代码交互。 此外,我们还使许多操作与没有索引或只有部分索引的情况兼容。 在 2024.2 版本中,大约 10% 的用户确实在整个同步和索引编制过程完成之前编写代码。 但我们的工作还没有结束。

我们现在的目标是改进分阶段同步,尤其是与 Gradle 的同步,进一步缩短代码可交互时间。 我们还在更新依赖项尚未解析时处理项目的用户体验。
同时,我们希望您能享受我们在缩短代码可交互时间方面取得的成果。 下载最新版本的 IntelliJ IDEA 并告诉我们您的想法!

本博文英文原作者:

Dmitriy Smirnov

Dmitriy Smirnov

Maarten Balliauw

Maarten Balliauw

image description

Discover more