在人工智能生成的代码盛行的时代,如何加快持续集成流程的速度?
如今,编码人员编写代码的速度远远超过了大多数 持续集成管道 检查代码的速度。2026年4月, GitHub首席运营官Kyle Daigle表示 ,他的平台每周要处理2.75亿次代码提交操作,到今年这一数字预计将达到140亿次,而2025年时这一数字仅为约10亿次。在同一篇帖子中,他还提到GitHub Actions在单周内所处理的操作量已经达到了21亿次,而2023年时这一数字仅为5亿次。 第二个数据说明了这些代码提交最终会去往哪里:也就是持续集成系统中。如果开发人员每天只进行几次代码提交,那么耗时15分钟的持续集成流程还是可以接受的。但当某个编码人员在一天下午就提交了10个 Pull Req
如今,编码人员编写代码的速度远远超过了大多数持续集成管道检查代码的速度。2026年4月,GitHub首席运营官Kyle Daigle表示,他的平台每周要处理2.75亿次代码提交操作,到今年这一数字预计将达到140亿次,而2025年时这一数字仅为约10亿次。在同一篇帖子中,他还提到GitHub Actions在单周内所处理的操作量已经达到了21亿次,而2023年时这一数字仅为5亿次。
第二个数据说明了这些代码提交最终会去往哪里:也就是持续集成系统中。如果开发人员每天只进行几次代码提交,那么耗时15分钟的持续集成流程还是可以接受的。但当某个编码人员在一天下午就提交了10个 Pull Request时,这个流程就会变成一个等待队列。人们需要等待测试结果,编码人员也需要等待系统重新尝试执行这些任务,这样一来,原本用于编写代码的时间就被浪费在了代码检查上了。
造成这种延迟的原因主要有几个,而针对每一个原因都有相应的解决办法。你可以通过以下五种方法来加快持续集成的运行速度:
- 查明时间被浪费在哪些环节上
- 将那些可以重复使用的资源进行缓存
- 在性能更快的硬件上运行相关任务
- 将测试任务分配到多个并行执行的进程中
- 跳过那些没有必要执行的操作。
在本文中,我们将依次介绍这些解决方法。你将学会如何找出GitHub Actions工作流程中效率最低的环节,如何使用固定的键值对来缓存依赖项和Docker构建层,以及如何将耗时较长的任务分配到性能更好的执行环境中。此外,你还会了解到如何将测试任务分散到多个并行执行的进程中,以及如何通过路径过滤、仅针对受影响对象的测试以及并发控制机制来跳过不必要的操作。
我们将会讨论的内容:
先测量数据,再优化流程
大多数团队都会试图猜测是哪个环节导致了效率低下,但他们的判断往往是不准确的。某个看似与测试相关的任务,实际上可能其中90秒都在用于安装相关资源,而只有30秒用于实际测试。
首先,你应该利用已经掌握的数据来进行分析。GitHub会显示每次任务运行的具体耗时情况,包括每个步骤所花费的时间。打开你工作中效率最低的那个工作流程中最近十次运行的记录,找出其中耗时最长的三个步骤。在分析数据时,应该使用中位数而不是最坏情况下的数值,因为偶尔出现的运行延迟可能是由于网络问题等原因造成的。
另外,还需要区分“等待时间”和“实际执行时间”。排队等待的时间、设置阶段所需的时间以及任务实际运行的时间,这些都需要采取不同的优化措施。如果某个任务在队列中等待了一分钟,那么任何针对测试环节的优化措施都无法改善其运行效率。
缓存依赖项和构建层
最快的工作就是那些永远不会重复进行的任务。每次运行都会在全新的机器上进行,因此如果没有缓存机制,就需要反复下载相同的包。
依赖项缓存相关说明解释了`actions/cache`的工作原理:你需要为它提供一个路径和一个键。如果该键与已保存的缓存匹配,那么文件就会被直接恢复;如果不匹配,相应的操作才会被执行,文件也会在任务结束后被保存下来。
一切其实都取决于这个键。通常情况下,系统会通过对锁文件进行哈希处理来生成这个键,因此只有当你的依赖项发生变化时,这个键才会改变。
- uses: actions/cache@v6
with:
path: ~/.npm
# 只有当锁文件发生变化时,键才会改变
key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
npm-${{ runner.os }}-
`restore_keys`这一配置项往往会被忽略。当找不到精确匹配的键时,系统会使用最接近的旧缓存版本来恢复数据。这样一来,虽然会安装一些新的包,但并不是所有的包都会被重新安装。需要注意的是,那些包含时间戳或提交哈希值的键是绝对不能重复使用的,因为这些值每次都会发生变化,所以每次运行时都需要生成新的缓存文件。
Docker构建过程也需要遵循同样的原则。Docker镜像是分层构建的,只有当上一层的内容没有发生变化时,下一层才会被重复使用。因此,应该先复制锁文件并安装依赖项,然后再复制源代码。这样,即使代码发生了变化,也不会导致安装步骤需要重新执行。为了在多次运行之间保留这些缓存数据,可以使用`BuildKit`与GitHub Actions缓存后端配合使用,将`cache-from`和`cache-to`的值设置为`type=gha`。
需要注意的是,这些缓存数据都是存储在远程服务器上的。每次恢复数据时都需要进行网络下载操作,对于那些体积较大的缓存文件来说,这个过程所消耗的时间可能会与重新安装依赖项所花费的时间相当。
在更快的硬件上运行
缓存机制可以避免重复执行相同的任务,而这种优化方法则是直接在性能更好的机器上执行相关操作。
对于私有仓库来说,GitHub提供的标准运行环境通常配备2个vCPU和7GB的RAM。Avrea是一种可以替代GitHub Actions运行环境的工具。你只需要将配置中的`runs-on: ubuntu-latest`修改为`runs-on: avrea-ubuntu-latest`,工作流程的其他部分保持不变即可。根据Avrea提供的数据,在仅使用硬件资源的情况下,任务执行速度可以提高大约2倍;而当缓存机制被启用时,执行速度甚至可以提升到10倍。
其他独立的研究结果也得出了类似的结论。 内置缓存是另一个关键环节,它与上述内容紧密相关。Avrea将其缓存存储在与运行器相同的数据中心中,因此数据恢复过程不会经过速度缓慢的网络。大部分缓存配置都是预先设置好的。 对于GitHub Actions而言,npm、pip、Go模块以及Cargo相关的缓存和包下载功能,在无需修改任何工作流程的情况下就能正常使用。针对Go、Bazel、Gradle、Turborepo、Nx和sccache等工具构建的缓存机制是在运行器上配置好的,其中某些工具可能需要稍作额外的工作流程设置。这样一来,团队就可以在无需为每种工具编写专门逻辑代码的情况下利用缓存功能。 其他供应商则采取了不同的实现方式。Depot提供了更快速的GitHub Actions运行器以及远程Docker构建服务,同时还运行着自己的持续集成引擎,该引擎能够支持GitHub Actions的工作流程。RunsOn则是自托管解决方案:它会在你的AWS账户中启动EC2实例,因此你需要为计算资源支付AWS的费用,并额外支付一年的固定许可证费用,而无需按分钟计费。GitHub自己提供的大型运行器适用于Team和Enterprise Cloud套餐,这些运行器拥有更多的CPU、RAM和磁盘空间,同时还提供静态IP地址和GPU等选项,费用也是按分钟计算的。建议查看各供应商的官方网站以获取最新信息,因为这些设置经常会发生变化。 一旦各项任务的执行速度都足够快,就需要确保它们不会依次等待执行。如果在一个运行器上运行大量的测试用例,就会形成典型的性能瓶颈。 首先应该将测试任务设计成独立的作业。代码检查、类型验证、单元测试以及构建过程通常彼此之间没有依赖关系。GitHub会默认并行执行这些任务,除非你添加了 接下来可以使用矩阵策略来进行任务拆分。矩阵策略会为每一种组合情况创建一个单独的测试作业,所有这些作业会同时执行。团队们经常用这种方法来针对不同的Node版本进行测试,而且这也是拆分测试任务的最简单方法。 Jest的 Playwright的用法也与此类似。在每个矩阵任务中运行 不过,拆分测试任务也存在一定的局限性。每个单独的作业都需要承担自己的准备开销,因此当拆分的作业数量超过一定限度后,虽然会增加并行执行的效率,但却会带来额外的成本。在同一个作业内部,pytest-xdist这样的工具会自动将测试任务分配给机器上的不同CPU核心来执行。 最后一种方法也是最简单的方法:不要运行那些没有必要运行的任务。 路径过滤器是开始使用这些方法的最佳选择。在工作流语法中,`paths`和`paths-ignore`键可以让工作流仅在某些文件发生变化时才运行。例如,文档文件夹的更改不应该触发后端的完整构建过程。 需要提醒的是:如果由于路径过滤器的设置,某个必要的状态检查从未被执行,那么拉取请求就会一直处于“待检查”状态。对于这些必要的检查,可以让工作流继续运行,但使用`if:`条件跳过相关任务——因为GitHub会将那些被跳过的任务视为已通过检查。 在单仓库环境中,可以进一步优化,只运行那些真正受到影响的测试。像Nx、Turborepo和Bazel这样的工具能够判断某个更改会影响到哪些包,从而自动跳过其余的测试。在Nx中,可以使用`nx affected -t test`命令;在Turborepo中,则使用`turbo run test --affected`命令。这两种工具都会将你的分支与`main`分支进行比较,因此在进行这种对比之前,请确保你已经查看了足够的Git历史记录——因为默认情况下,`actions/checkout`命令只会获取最近的一个提交。 大多数提交所影响的只是大型代码库中的很小一部分内容,因此这些优化措施带来的节省效果是累积的。当有很多代理同时处理许多只涉及一两个包的小型拉取请求时,这种效果会更加明显。 最后一点:不要为那些没有人真正需要的运行任务支付费用。当你连续两次推送代码时,第一次进行的运行就已经过时了。可以使用并发控制组来取消这次多余的运行。 随着人工智能工具产生的提交次数不断增加,这一点就变得更加重要了。代理可能会每小时多次更新某个分支,而每次推送都会触发一次完整的运行过程。不过,在部署工作流中不要使用这种并发控制机制——因为在部署过程中中途取消运行可能会导致系统状态异常,因此应该将这类任务放入队列中依次执行。 首先进行测量,这样才能确定在四种优化措施中,哪一种真正值得你花费时间去实施。使用稳定的键值对来缓存数据,并合理安排Dockerfile的编写顺序,确保那些耗时较长的构建步骤能够被安排在后面执行。将那些耗时较多的任务分配给性能更好的运行环境,并亲自对比不同的工具提供商,看看哪种方案更适合你的需求。对于测试任务,可以根据实际情况进行拆分处理,直到设置阶段所占的时间变得过长为止。然后,通过使用路径过滤器、仅针对受影响部分的测试以及取消过时的运行任务来进一步减少不必要的工作量。 每次只进行一项优化修改,每修改完一项后都要重新测量运行时间。对于那些每天要运行50次的任务来说,节省2分钟的时间远比为那些只运行1次的任务设计复杂的优化方案更有意义。 希望你喜欢这篇文章。你可以通过在LinkedIn上与我联系来与我保持交流。并行执行并拆分测试任务
needs指令;因此,那些只是出于习惯而添加的needs语句应该被删除。strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4]
steps:
# 每个作业负责执行测试套件中的四分之一内容
- run: npx jest --shard=${{ matrix.shard }}/4
--shard选项会根据测试文件的分布情况来将整个测试套件分配给不同的作业。如果各个文件的执行时间大致相同,那么使用4个作业来拆分测试套件可以将原本需要12分钟的测试过程缩短到大约3分钟左右(还包括准备时间)。不过,如果某些文件的执行耗时较长,那么单独为这些文件分配一个作业也会导致整体执行时间变长,因此需要对测试文件进行合理分类。npx playwright test --shard=1/4命令,最后再将所有测试结果合并起来进行分析。每次运行时减少工作量
concurrency:
group: ${{ githubworkflow }}-${{ github/ref }}
# 当有新的推送到来时,取消之前的运行任务
cancel-in-progress: true
综合运用这些方法
相关文章
通过Codex及AI编程助手学习代理编程技术
像Codex这样的AI编程助手能够阅读你的代码库,编辑多个文件,并在执行复杂任务时运行相应的命令和测试。在Codex中,AGENTS.md文件用于存储项目的永久性配置指令,而config.toml文件则用于保存编程助手的配置信息。 我们刚刚在freeCodeCamp.org的YouTube频道上发布了一门课程,这门课程会教你如何为编程助手提供正确的上下文信息、合理规划工作流程、控制其访问权限,并验证每一处修改内容。该课程由Scrimba的教育负责人Tom Chant主讲。 你将通过一些实际的任务来学习这些知识,其中包括技能测试、配置文件编辑等相关练习。这门课程适合那些希望将AI技术融入日常工作
阅读全文
云服务模型解析:IaaS、PaaS与SaaS的区别
你很可能每天都在使用云服务。当你查看Gmail、参加Zoom会议,或者在Slack上与团队交流时,其实都是在使用由云端提供的软件。 但你并不需要管理这些软件运行的服务器,也不需要维护底层的基础设施。你只需要登录后就可以开始工作了。这种服务模式被称为 软件即服务(SaaS) ,很多人多年来都在使用它,却不知道这个术语的存在。 SaaS只是三种主要的云服务模型中的一种。另外两种模型是 基础设施即服务(IaaS) 和 平台即服务(PaaS) ,它们能让你对所使用的基础设施和软件拥有不同程度的控制权。了解这些模型的区别,有助于你理解云计算的相关概念,并为自己的项目选择合适的服务模式。 在这篇文章中,我
阅读全文
谷歌开源了AX这一基于Kubernetes架构的自动化AI代理管理工具。
谷歌已将AX这一专为管理自主AI智能体的工作负载而设计的工具开源。AX运行在名为“Agent Substrate”的运行时环境中,将这些智能体视为具有状态变化的实体。该工具能够高效地暂停及恢复任务的执行过程,从而优化性能,并在智能体处于空闲状态时减少延迟。它还配备了采用Kubernetes架构设计的控制机制,用于管理智能体的任务与资源。 作者:Olimpiu Pop
阅读全文
Azure Logic Apps Standard版本现已推出本地命令行工具测试版
微软发布了适用于Azure CLI的logicapp扩展程序的公开预览版。该扩展程序为Logic Apps Standard提供了本地项目创建、工作流编写、运行时生命周期管理、连接器配置管理、运行检查以及测试框架等功能,而这些功能此前都需要通过VS Code扩展程序来实现。产品团队将这一终端界面称为实现人工智能辅助开发的关键工具。 作者:Steef-Jan Wiggers
阅读全文