本文由 Omer Dunay、Kun Jiang、Nachi Nagappan、Matt Bridges 和 Karim Nakad 共同撰写。
在 Meta 内部,无论从代码行数还是从用户数量来看,Python 都是用得最多的编程语言之一。我们每天都有成千上万名开发者使用 Python 发布新功能,修复漏洞,开发最复杂的机器学习模型。因此,为 Python 开发者提供最先进的工具,确保他们能高效工作,这一点至关重要。
今天,我们介绍的是 Wasabi,这是一种实现了语言服务器协议 (LSP) 的 Python 语言服务,旨在帮助开发者更轻松和更快速地使用 Python。Wasabi 提供了一系列先进功能协助开发者编写 Python 代码,具体包括:
此外,Wasabi 服务适用于任意平台,可以部署到多个代码存储库和各种开发环境(例如 VSCode、Bento Notebook)中。自首次推出以来,Wasabi 已经被 Meta 名下的 Facebook、Instagram、Infrastructure 等团队的数万名 Python 用户所采用。
图 1:Wasabi 的全局符号自动补全功能示例
语言服务的主要设计要求是低延迟/用户响应性。自动补全建议、lint 和快速修复应该在开发者输入时立即显示出来。
Meta 以 monorepo(单体仓库)的形式组织代码,这意味着开发者在开发过程中可以访问所有 Python 文件。这种方法给开发者工作流程带来的主要优势在于可发现性更高、透明度更高、更易于共享库以及增强团队间的协作。它还给构建开发者工具,如需要处理数十万个文件的语言服务,带来了特殊挑战。
规模问题是我们试图避免使用业内的现成语言服务(例如 pyright、jedi)来执行这些操作的原因之一。那些工具大多都是在相对小型到中等的项目工作空间下构建的,在这些工具所假定的工作背景下,那些需要 o(repo) 信息的操作都是针对涉及数千个文件的大型项目。
以针对未定义变量的“自动导入”快速修复功能为例。为了能够提示语言服务器读取所有源文件所需的所有可用符号,快速修复功能将对它们进行解析,并在内存中缓存所有已解析的符号,以响应请求。
虽然对于中小型存储库而言,这可以扩展为在开发计算机上的单个进程中执行,但此方法在单体仓库用例中无法扩展。读取和解析数十万个文件可能需要等待几分钟,这意味着启动时间缓慢,开发者也会感到苦恼。转移到内存中进行缓存可能有助于缩短延迟,但单台计算机的内存也可能承载这些文件。
例如,假设一份普通 Python 文件需要大约 10 ms 的时间来解析和提取标准错误可恢复解析器中的符号。这意味着,完成 1,000 个文件的初始化需要 10 秒钟,这个启动时间相当合理。而完成 100 万个文件的初始化则将花费 166 分钟,这个启动时间显然太长了。
离线+在线处理:
为了支持 Meta 级存储库实现低延迟,Wasabi 支持两个解析阶段,由外部索引器完成的后台处理(离线)和由本地更改的“脏文件”完成的本地处理(在线):
因此,所有 Wasabi 功能均具有较低延迟,用户可以在输入代码时无缝使用这些功能。
注意:Wasabi 目前不处理 glean 编入索引(每隔几小时发生一次)的修订版与用户当前拥有的本地基本修订版之间的潜在差异。我们计划将来再增加此功能。
图 2:Wasabi 的高层体系架构
某些情况下,受存储库的规模影响,结果集中可能有许多有效建议。以针对“utils”符号的“自动导入”建议为例。可能有许多模块在整个存储库中都定义了一个名为“utils”的类,因此我们新增了结果排名,确保用户在顶部能看到最相关的建议。
例如,根据以下因素对自动导入内容进行排名:
为了评估排名是否有用,我们测量了被接受建议在建议列表中的次序,我们发现几乎在所有情况下,被接受的建议均为排名前三的建议之一。
在 Meta 内部发布 Wasabi 进行了几次试运行后,我们收到了来自开发者的大量积极反馈。以下是 Instagram 软件工程师提交给我们的一条反馈:
“如今我已经使用 Wasabi 好几个月了,它大大提升了我的工作效率!在 Instagram 服务器上工作,尤其是处理较大文件时,pyre 的警告发出的相当缓慢。用了 Wasabi 后,它们的速度快得像闪电 😃!”
“我每小时都要使用好几次拼写错误检查和自动导入等功能。这可能使我的开发工作流程平均快了 10%(这只是粗略猜测,实际提速可能更多,但肯定不会低于 10%),这真是相当巨大的改进!”
如上所述,Wasabi 带来了重大改变,让开发者能够高效愉快地工作。
为了定量评估 Wasabi 为 Python 开发者创造了多大价值,我们曾考虑过许多可以用来衡量 Wasabi 影响力的指标。最终,我们决定使用名为“编程速度”的指标来评估开发者编写代码的速度。实质上,编程速度是在编程阶段中对某个特定 diff(代码更改集合)所用时间的反函数。编程阶段的开始时间为开发者从源代码控制存储库签出时的时间戳,截止时间为创建 diff 时的时间戳。我们还根据 diff 中更改的代码行数(diff 大小指标)对编程速度进行了规范化,以抵消任何潜在差异。我们认为,“编程速度”的值越大,开发者编写代码的速度就越快。
图 3:编程速度指标公式
定义了指标后,我们开展了一项实验来评估 Wasabi 给开发者带来了哪些变化。具体而言,我们选择了约 700 名之前从未用过 Wasabi 的开发者,然后按 50:50 的比例将他们随机分成两组。实验组的开发者使用 Python 编程时启用了 Wasabi,而对照组的开发者编程时则没启用 Wasabi。然后,我们比较了两组开发者启用 Wasabi 前后的相对指标值的变化情况。根据两组的对比结果,我们发现实验组的开发者在开始使用 Wasabi 后,编程速度的中位数增加了 20%。与此同时,对照组的编程速度则全程无任何显著变化,这也在我们意料之中。
图 4:实验组和控制组在实验组启用 Wasabi 前后的实测编程速度对比。
随着 Python 的空前发展,能够投身此领域让 Python 变得更完善、更易于使用真是令人振奋不已。Wasabi 凭借其先进的功能,有效提升了 Meta 开发者的工作效率,使他们能够更快、更轻松地用 Python 编程,给他们带来了良好的开发者体验。我们希望此原型和开发成果能够让 Python 社群的更多人受益。
如需了解有关 Meta Open Source 的更多信息,请访问我们的 Open Source 网站、订阅我们的 YouTube 频道,或在 Twitter、Facebook 和 LinkedIn 上关注我们。