Rust是一种一旦了解就会产生使用欲望的语言,Rust 语言连续八年蝉联 stackoverflow 开发者调查问卷 最受欢迎编程语言榜首就是最好的证明。
但比起“最受欢迎”的连胜纪录,增长的使用率更加值得关注。与2022年的调查相比,它在所有受访者中增长了3.7个百分点,现在紧随 Go 之后。
人们对 Rust 语言普遍的抱怨来自没有太多的 Rust 工作岗位。然而,Rust 语言已经在一些至关重要的基础领域开始铺垫。是否普遍使用不是评价一门语言的唯一标准,更好的方法是看这个工具在哪里被使用以及这个使用案例的重要性。
这也是本文的写作目标。希望大家通过这篇文章对 Rust 语言有一个全面且客观的认识。
在写本文之时,TOIBE 编程语言九月排行榜出炉,Rust 排名上升到第 17 位。
并且,Jetbrains 也宣布发布独立的 Rust IDE : RustRover。拥有独立的商业 IDE,不是说这个 IDE 最好,而是意味着 Rust 迈入主流语言行列。
总之,今天是 Rust 出圈的一年。
“本次报告的所有内容都来自于互联网公开信息,如有错误或不宜在本报告中提及的内容,请及时告知。往年的 Rust 生态报告参见附录。
Rust 语言及其生态现状总览
Rust 语言现状:特性、优势和挑战
Rust 开源社区治理:组织结构、贡献者以及影响力
Rust 生态总览:主流库和框架
深入 Rust 应用领域
Rust 在全球商业巨头中的应用
Rust 在高科技和工业领域中的采用案例
Rust 语言实践经验漫谈
如何从成功的 Rust 项目案例中学习:项目背景、架构设计、实现亮点
Rust 与 C/Cpp 交互实践:FFI 使用和安全性
AI 时代 与 Rust 语言学习
Mojo vs Rust
让 AI 成为自己的学习助手
附录:往年的 Rust 生态报告
要了解 Rust 语言及其生态现状,我们依然可以从 Rust 语言设计原则出发。
而 Rust 语言的设计原则本身也是不断发展变化而沉淀的。在 Rust 诞生的开端,是由 Rust 团队内部一些可以主导 Rust 语言设计的人员遵循共同的某种思想来创造 Rust 。在前 Rust 核心团队成员 Brson 在 2021 年写的《造就 Rust 的无名英雄》一文中透露了早期引领 Rust 设计的重要幕后人物戴夫·赫尔曼( Dave Herman)为 Rust 发布稳定版 v1.0 所做的诸多奠基性的贡献。
Rust 稳定版 v1.0 发布之后,又经历了六年的发展(2015-2021),由 Rust 语言团队作为 Leader 的 Niko 提出了更加具体和广泛的 Rust 语言原则《Rustacean Principles 》 ,其中不仅仅包含了 Rust 语言该如何设计的原则,而且还包含了 Rust 语言开源社区成员(Rustacean)们如何更好地参与社区活动的原则。
这些原则可以概括为以下三个重要方面:
Rust 是什么?
Rust 语言是一种让每个人都能构建可靠高效软件的语言。
一个专注于创建、设计和维护该(Rust)语言及其生态系统的开源社区。
Rust 语言设计:Rust 如何为用户赋能,Rust 语言的设计是以下原则的权衡。
与支持性和生产力相矛盾。
通过以某种方式向Rust程序暴露所有核心系统功能,并应该使用 unsafe Rust 来避免让用户降级去使用 C 。
与支持性和生产力相矛盾,因为透明性通常需要暴露更多细节。
通过让 Rust 变得更加透明来保证透明性,努力避免那些会对全局产生成本的特性(即即便用户未用到的特性也会在运行时产生成本的特性)。
与 可靠性和性能相矛盾。
通过保证版本的稳定性和打造繁荣的生态来提升生产力。
与可靠性 和 多样性 相矛盾。
通过优化开发中体验,提供更好的工具来增强支持性。
与 支持性 和 某种情况下的生产力 相矛盾,用户可能无法从其他语言的某些习惯中获得便利。
与 透明性 和 多样性 相矛盾。许多优化依赖于事物发生的顺序和方式的透明度。
依赖于零成本抽象和只提供捕捉用户意图的适当的细节。
与 生产力和支持性相矛盾。因为可靠要依赖各种检查,这些检查会影响系统的构建难度。
与 多样性 相矛盾,因为可靠性的能力总是有限的,那么也会影响用户所能构建系统的领域范围。
依赖类型安全和使用多种机制鼓励用户不隐藏发生错误的条件来保证可靠性
可靠性(⚙️ Reliable)。如果它编译,它就可以工作。
高性能( Performant)。既高效执行又使用最少内存。
支持性( Supportive)。语言、工具和社区随时为用户提供帮助。
生产力( Productive)。让工作事半功倍,短时间内构建高质量系统。
透明性( Transparent)。让用户可以预测和控制底层细节。
多样性( Versatile)。你可以用 Rust 做任何事,从简单的脚本到复杂的系统,通用语言,多领域应用。
**Rust 社区如何治理才能更贴近 Rustacean
**:用于帮助 Rust 核心团队和社区贡献者良好合作。
善良体贴。相互尊重彼此才是构建 Rust 未来的基础。
给用户带来快乐。首要目标是让 Rust 用户更有效率和能力。希望人们喜欢使用 Rust,如果他们愿意,也喜欢参与它的社区。
畅所欲言地表达自己。带上你的专业知识,并愿意为你认为正确的事情进行辩论。
认可别人的知识。没有人能垄断好的创意。Rust 团队需要汲取优秀的建议来改进设计。
从小处开始。寻找完美的设计需要迭代。大处着眼,小处着手;当你了解更多时,不要害怕改变。
跟进。说你会做的,做你说的。
把爱传出去。Rust项目成员需要识别有潜力的贡献者,有义务去发展新的成员,并且当好教练的角色。
信任和委托。赋予他人权力意味着愿意让他们以他们认为最好的方式做出决定。
总的来说,这些原则规范着 Rust 语言的演进方向。
那么,截止 2023 年的今天,让我们依据这些原则来再次审视 Rust 语言及其社区和生态,看看 Rust 语言有没有成为它想成为的语言。
2023 年,Rust 距离 2015年5月稳定版1.0 发布已经经历了八个年头,发布了71个稳定语义化版本,2015、2018、2021 三个 Edition 版本。
这八年中,Rust 语言提供的特性不仅仅在内存安全上取得了成果,而且在工程架构方面也得到了很多领域实践的验证与认可。
目前,Rust 已经进入了更加成熟与扩大应用规模的阶段。
2023 年初 Rust 语言发布了 1.67 版本,截止到今天这篇文章为止,已经发布到了 1.72稳定版,10月5号马上发布 1.73 稳定版。参考 releases.rs
Rust 语言更新改进是全方位的,包括六个主要方面:语言、编译器、库(core/std)、稳定API ,Rustdoc、Cargo 、兼容性变化以及不影响稳定接口的内部改进。
我们可以按 Rust 设计原则来对这些更新进行归类,当然,这里不会把每一条更新都列出来,但会归纳一个整体趋势。
允许在所有repr(Int)
枚举类型上指定明确的判别标准
允许仅在生命周期上有所不同的相同类型之间进行转换
如果 impl Trait
有 super trait 有 #[must_use]
则触发 must_use
lint
将 Sized
谓词定义为共归的(Coinductive,或称反向归纳),允许循环
稳定efiapi
(用于定义兼容 UEFI 接口的函数)调用约定
启用s390x-linux的 Sanitizers
为了确保BinaryHeap的不变量(Invariant),对peek_mut()
进行泄漏放大(Leak Amplification)处理(这个 Leak amplificatioin 是一种非常巧妙的策略,深入了解这个 PR 你会受到新的洗礼)
对于未对齐的对齐字段的引用现在将成为一个严格的错误
在指针解引用处插入对齐检查作为调试断言。这样可以在运行时捕获未定义的行为
在编译时常量求值期间始终检查对齐
Cargo 在通过SSH克隆索引和依赖时没有执行SSH主机密钥验证。攻击者可以利用此漏洞进行中间人攻击。此漏洞已被分配CVE-2022-46176。所有在1.66.1版本之前的Rust版本中,包含Cargo的都存在漏洞,升级到 1.66.1 以后的版本则无问题
启用LLVM编译的BOLT功能
基于数据流分析添加新的MIR常量传播
为 Vec -> VecDeque
添加 O(1) 的转换保证
Const 上下文稳定了 VecDeque::new
升级至Unicode 15
将libstd的libc更新到0.2.135
在文档中添加Rustdoc警告,用于无效的HTML标签
允许在模式中使用 ..=X
添加 cargo remove
以删除 Cargo.toml 中的依赖项
放宽对 asm!
操作数的顺序规定
NonZeroXxx布局保证
添加关于 Cell
的内存布局的文档
PhantomData布局保证
添加 armv5te-none-eabi
和 thumbv5te-none-eabi
作为 Tier 3 目标
增加对链接 macOS 通用库的支持
不在wasm32-wasi
上导出 __heap_base
和 __data_end
只在wasm32-unknown-unknown
上导出 __tls_*
为除 C
或 cdecl
(已经支持)之外的调用约定启用可变参数支持
为索尼PlayStation 1添加 Tire 3 目标
提升 {aarch64,i686,x86_64}-unknown-uefi
为 Tier 2 目标
为 QNX Neutrino RTOS 增加 Tier 3 no_std
AArch64/x86_64
支持
将 powerpc64-ibm-aix
添加为 Tier 3 目标
稳定 raw-dylib
, link_ordinal
, import_name_type
和 -Cdlltool
将 aarch64-apple-darwin
的目标 CPU 设置为 apple-m1
将 loongarch64-unknown-linux-gnu
提升至 Tier 2 目标
从上面罗列的一些语言改进特性中,可以简单地概括 Rust 语言稳定版在 2023 年的演进趋势:
持续提升 Rust 语言的可靠性和安全性
持续提升 Rust 语言在多样化领域的支持,比如对 Windows、WebAssembly、Linux、Android、索尼 ps,还有 loongarch64 都有支持。另外,其实也添加了OpenHarmony *-unknown-linux-ohos
为 Tier 3 目标。
稳定了很多 API 对于提升生产力和降低 Rust 学习曲线是很有帮助的。
Rust 2023 的发展目标是为 2014 Edition 服务的,让 Rust 更加成熟并且让 Rust 应用的规模更加扩大,即,让 Rust 遍布四海。
除了今年稳定版已经发布的那些特性之外,Rust 语言还有一些重大的改进正在进行中。
异步编程向真正的零成本抽象迈进。让 Rust 异步编程遍布四海,那么在高性能、生产力和多样性上面更加重要。目前异步编程已经在生产环境基本可用,但是在零成本抽象的目标上还差很多工作,具体可以查看 wg-async roadmap 。其中马上要稳定的特性是 TAIT(Type Alias Impl Trait) 。该特性允许为 impl Trait
创建类型别名,impl Trait
是静态分发,这样就可以在trait 关联类型(ATPIT, Associated type position in traits)中使用 impl Trait
,尤其可以改进现在异步编程模型,有利于即将在 1.74 版本中稳定 async fn in traits
的 MVP (最小化可用)功能。
“Rust 团队在评判这个功能 MVP 标准的时候也是结合了实际生产中的典型案例进行改进,包括 AWS SDK 、 开源框架 tower 、嵌入式异步运行时 embassy以及 Fuchsia OS 网络栈、微软内部工具等实际使用案例的各种情况来确定 async trait 到底该如何设计。
泛型关联类型(GAT)的持续完善。GAT 自从在去年(2022.10)稳定了 MVP 版本以后,极大地提升了 Rust 语言的抽象表达能力,帮助众多知名开源项目在维持零成本抽象的基础上简化了抽象架构。但是还有很多未解决的问题,比如如何保证 GAT 的向后兼容性,如何让 GAT 更易于使用等等。
为 Unsafe Rust 定义规则。在 Rust 语言发布的最初,Unsafe Rust 使用起来好像很简单,但是随着 Rust 的发展,Unsafe Rust 变得越来越复杂,官方需要明确一些规则,为开发者及丝滑的安全检测工具提供方便。一些正在进行的工作包括:
指针溯源(Strict Provenance),目前已经实现了 Strict Provenance MVP。由 [feature(strict_provenance)]
特性门开启。这个安全规则让 Rust 具有极其严格的指针来源要求。也就是说,如果开发者想将某个东西视为真正的指针,可以进行偏移(Offset)和解引用操作,那么从该指针到开发者尝试访问的原始分配之间必须有一个不间断的监管链。如果开发者在中途将指针转换为了地址,则无法再从地址转换为指针(地址和指针转换滥用是 C 语言中安全 Bug 的温床)。这个安全规则的落地,会让 Rust 指针使用更加安全,目前还未进入 FCP。
为了更加准确地定义 Unsafe Rust 的操作语义,官方成员 Ralfj 发起了 MiniRust 项目,该项目用于定义Rust语义规范,为 MIR(Rust 语言中级中间语言)提供基石,也可以为 Miri 或 Kani 这样的检测工具提供语义基础。由此也创建了由 Ranfj 领导的 操作语义团队(opsem Team)。
稳定 MIR API。像 Miri 和 Kani 这样的工具属于动态验证工具,但是它有受限范围,比如无法对 FFI 进行验证。所以需要提供静态验证的工具,那么由官方来提供稳定的 MIR API 就成了需求。所以官方开辟了 stable mir项目,目前积极更新的是 Rust 编译器内部的 rustc_smir crate。
Rustc Trait System重构计划。今年 Rust 官方成立了 类型团队,专门来处理 Rust 语言团队委托的类型系统设计和实现的相关工作。因为 Rust 语言类型系统是重中之重,而 Rust 语言类型系统一直有技术债需要处理,所以专门成立这个内部团队。主要的工作会涵盖下一代借用检查器 Polonius 的设计与实现(目前已经引入 Nightly ,但是因为性能问题没有面向大众稳定),以及 trait 系统重构(chalk 虽然实现了有几年,但它不是 Rust 的长期解决方案,但目前仍保留其实验目的)等。目前 trait 系统重构的优先级更高。同时,类型团队也有形式化定义类型系统的职责,以此推动 Rust 语言规范的落地。目前 a-mir-formality 是 Rust 类型团队开始进行的类型系统形式化工作。上面介绍的 GAT/TAIT 等特性也是由类型团队来推动。类型团队计划在 2027 年底建立一个能够满足Rust语言所需新功能的可靠、可测试和有文档支持的类型系统平台。但这个目标也是分阶段的,在今年年底的目标是将重构的新的 trait 系统求解器替换掉旧的,并且将 a-mir-formality
形式化类型系统融入到语言设计过程中。(这是否意味着 Rust 语言将从一个最初由工程实践驱动的语言走向学院派?我的期望是它可以平衡实践与学术,目前看是这样的)。目前新的 trait 求解器已经可以通过使用 rustc 标志 -Ztrait-solver=next
在 Nightly 上使用。
Rust 编译后端 GCC 的支持。目前 Rust 官方正在进行一个 Rust 后端 GCC 支持 rustc_codegen_gcc
。另外一个由 GCC 社区发起的 GCC Rust 前端 Rust-GCC 项目,Rust-GCC 的动机包括推动 Rust 的采用,复用现有的 GCC 改进,以及为更多的系统提供后端支持。项目的当前状态包括处理 const generics(常量泛型)、intrinsics(内置函数)、borrow-checking(借用检查),以及针对旧版本的 libcore 进行定位。Rust-GCC 在 2022 年共有超过 50 位贡献者,包括多名学生、实习生、GCC 开发者以及 Rust 核心团队成员。Rust-GCC 的详细进展可以参考 GCC Rust 前端 2023 报告 pdf。
Rust 基金会安全计划。随着 Rust 语言的流行度不断攀升,其优点在开源生态系统的各个角落以及更广泛的领域都得到了越来越多的认可。就像开发人员越来越多地转向 Rust 来构建高性能的系统一样,一些重要的政府机构也开始将 Rust 视为更安全的编码解决方案,特别是用于改善软件供应链的安全性。Rust 作为一种内存安全和高性能的语言的卓越声誉,以及其可见度、流行度和采用率,每天都在增长。然而,为了适当地支持 Rust 的未来和其不断增长的社区,并确保 Rust 继续履行其安全和安全的承诺,Rust Foundation 认为必须采取积极的措施来加强和扩大生态系统中的安全性。这就是为什么他们在 2022 年 9 月启动了安全倡议,得到了 OpenSSF 的 Alpha-Omega 项目和 Rust Foundation 铂金会员 AWS 的慷慨支持,以及新加入的铂金会员 JFrog 的技术支持,Wiz 的基础设施支持,以及铂金会员 Google 的咨询。在 2022 年 12 月至 2023 年 7 月期间,Rust Foundation 安全倡议的工作主要集中在以下几个优先领域:
雇佣 Rust Foundation 安全工程专家:Rust Foundation 已经聘请了全职的软件安全专家,他们正在与 Rust 项目的领导层合作,确定初始的安全优先事项,开始对项目和社区进行全面的审计,并开始设计实际的解决方案。
对 Rust 生态系统进行安全审计:Rust Foundation 和 crates.io 团队正在合作,以提供更深入的 crate 安全洞察,并更突出地展示 crate 安全信息。他们的工作目前集中在软件供应链安全上。评估工作包括泄露的秘密、恶意 crate 检测和安全最佳实践评分模型。
对 Rust 生态系统进行威胁建模:威胁建模练习使 Rust Foundation 和 Rust 项目能够更好地理解安全审计识别的风险。在开发以下四种威胁模型时,基金会已经与 Rust 项目的 crates.io 团队、基础设施团队、安全响应工作组以及安全代码工作组进行了咨询,此外还咨询了特定的外部利益相关者。我们期待尽快分享所有威胁模型的详细信息。
在 Rust 生态系统中倡导安全实践:Rust Foundation 团队已经编写了一份 RFC ,以便在满足一系列安全阈值后隔离问题 crate。如果获得批准,这个功能将使得在公开使用 crate 时,可以在 crates.io 基础设施内进行安全检查以确保其安全性。此外,Rust Foundation 团队已经开始与基础设施团队接触,开始记录 Rust 项目中的访问控制配置和取消配置的过程。
基于研究开发工具、特性和建议:Rust Foundation 安全工程师 Walter Pearce 创建了一种名为 Painter 的工具,该工具旨在解决使用其他工具(如 Cargo Audit)时的问题,并确定风险。此外,Rust Foundation 和 crates.io 团队在 2023 年 6 月合作发布了一份声明,阐述了如果任何一方收到法律约束的数据请求,我们共同的一般处理方式。
开发文档以揭示 Rust 生态系统中的安全性:通过在技术 Rust 文档中概述安全风险、漏洞和考虑因素,开发人员将更好地遵守安全最佳实践,并在部署 Rust 代码时做出明智的选择。Rust 的高质量安全文档的扩展将使开发人员能够在 Rust 开发过程的早期阶段识别并解决潜在的漏洞,防止常见的安全陷阱,并更好地教育社区关于 Rust 现有的安全优势。
解决通过研究识别的 Rust 安全问题:尽管初始的 Rust 安全审计尚未完成,但我们负责研究 Rust 安全状况的工程师已经识别并优先解决了几个安全问题。在 Rust 生态系统中,我们将通过适当的渠道报告更多的安全问题,包括在必要时通过 Rust 项目安全响应工作组。
Rust 没有语言规范这件事,这几年一直是某些 Rust 反对者口中的“弊病”之一。从 2023 年开始,这个情况应该会得到改善。
首先,由 Ferrous Systems 公司联合 AdaCore 共同创建的 Ferrocene语言规范(FLS)已经正式发布。该规范主要用于 Ferrous Systems 和 Adacore 合作的项目 Ferrocene,旨在将经过验证的Rust工具链引入安全关键环境。FLS 主要是为了以标准化的形式记录rustc 编译器的当前行为,以便进行资格认证。如果FLS与编译器行为不一致,规范将会更新。截止目前, Ferrocene 正在进行ISO 26262 和 IEC 61508 安全认证,预计十月份发布。未来还会进行更多安全认证。
“小知识:ISO 26262标准定义了四种汽车功能安全(Function Safety)完整性等级 (ASIL) A,B,C和D,其中 'D' 代表最严格等级。而IEC 61508 (代表工业自动化)则规范了电机电子的相关软、硬件及系统的安全强度, SIL 3 为单个产品的最高等级。除此之外,还有核工业、航天、石化、电网、医疗软件等各种安全认证标准。
除此之外,Rust 语言官方团队也正式接受了 《Rust Specification》的 RFC #3355
。意味着,Rust 语言官方团队正准确起草 Rust 语言规范,目前 Rust 基金会和 Rust 领导委员会已经批准这一计划,准备招聘专业的撰稿人来全职起草这份官方的 《Rust 语言规范》,并且也打算让这个撰稿人能成为语言规范开发过程中的领导者。该规范的进展参见 #113527
。
在这里值得声明的是,Rust 官方团队并不希望用户被《Rust 语言规范》这个名称误导为它就是 Rust 语言的权威的标准。这也是官方没有将其命名为《Rust 语言标准》的原因。《Rust 语言规范》只是对 Rust 语言最终完整性和准确性的承诺。另外官方团队还将在正式发布之前考虑“规范”一词可能带来的“法律影响”。Ferrocene 团队的 Leader 也声称,任何编译器的需求文档,无论什么形式,都会被称为“规范”,所以 Ferrocene 语言规范也采用了“规范”而非“标准”,尽管 Ferrocene 需要安全认证。
关于 Rust 语言自身是否需要一个 Rust 标准,库团队 Leader Mara 专门写过一篇文章论证过这个问题。该文章提到 C 和 Cpp 标准由各自的 ISO 委员会制定,其中 C 标准超过 500 页,Cpp 标准近 2000 页。遵循这些标准,很多公司研发了自己的编译器,公司投资参与标准化委员会的一个原因是能够影响语言发展的方向,尽管这可能会相当昂贵。
但是 Rust 语言是现代语言,它诞生在一个开源协作和跨平台软件相当普遍的年代,这种情况与 40 年前 C/Cpp 诞生的年代大有不同。Rust 语言,只有一个并且在未来也会保持唯一的官方编译器。而 Rust 基金会拥有 Rust 语言的商标。如果需要一份 Rust 语言标准来定义 Rust 编译器,那么也不应该是 C/Cpp 标准委员会那种形式。
Rust 语言作为一个开源的项目,它演进的方式是非常现代化的。Rust 语言每六周发布一个稳定版的编译器,意味着,每六周就会改变一次 Rust 编译器的“含义”。如果要对 Rust 语言进行大规模更改或添加新的特性,则需要通过 RFC 流程来完成,这些文档都需要公开评审。一旦有官方权威成员认为提案达到可接受状态,并且最多两名非权威成员确认之后,就会进入为期 10 天的最终评审期(FCP)。一旦FCP完成并且RFC合并到RFC存储库中,该文档将在RFC书中提供,并在GitHub上开启一个跟踪问题以追踪新功能或变更的开发进展。
然而,新功能也不一定保证会出现在未来的稳定版本的Rust中。一旦该功能完全实施,所有未解决的问题都得到解决,关于未来也不再有持续的讨论,权威团队的成员可以提出稳定化FCP。一旦一个特性稳定了,就不能移除它。Rust 语言对稳定性有严格的要求,非常注重向后兼容性。官方通过 crater工具来检测 Rust 编译器发布过程中可能出现的回归问题。
除了语义化版本之外,Rust 语言还提供版次( Edition )。这是为了允许 Rust 语言能以不兼容的方式进行一次改变。比如之前添加 async/await 关键字,为了不破坏生态系统中一些 crate 中以这两个词命名的代码,就以 Edition 来发布。类似于 Cpp 98 / Cpp11/ Cpp 20 ,但Rust Editions可以混合使用,并且可以根据 crate 进行选择。例如使用 Rust 2018 Edition 编写的代码可以很好地使用 Rust 2015 Edition 和 Rust 2021 Edition 编写的依赖项。
Rust 在这样的演进之下,拥有一个帮助保证维护 Rust 稳定性的语言规范,其实也是非常有必要的。前面提到的 Ferrocene 语言规范团队也非常希望 Rust 官方团队以 FLS 为起点来构建 Rust 官方的语言规范。但问题是,Rust 语言是否需要一个标准?即类似于那些 ISO 或 ECMA 标准化机构所做的工作。但是对于像 Rust 语言这样演进的一门语言来说,将责任移交给一个标准组织意味着放弃官方团队的控制权,这几乎没有任何好处,官方团队将失去塑造他们认为最好的流程的能力,也许再也无法保证一个符合开源社区标准的开放和包容的环境。
许多公司和个人参与 C++ 标准化以影响该语言,以向该语言添加自己的特性。然而,对 Rust 规范的努力并不是为了改变 Rust。对于 Rust 来说,标准化的目的是:
拥有标准和准确定义的语言特性规格说明文件。
一个开放的语言演变过程。
保证稳定性。对于 2
和3
来说,Rust 其实已经做到了,现在缺乏的就是 1
。Rust 语言规范就是填补这个空白。
Rust 语言自诞生以来,就把开源社区作为语言的一部分。Rust 语言社区一直都是开源社区的典范与榜样。任何事物的发展过程都不是一帆风顺的,Rust 语言开源社区也是一样的,需要在不断的犯错和修正的循环中成熟。
2023 年 Rust 开源社区出现了两件不得不说的大事。第一个是 Rust 基金会修改 Rust 商标政策,另一个是 RustConf 主题演讲作者被降级的事件。这两件事在社区中产生了很大的影响,所以这是不得不说的事情。让我们简单回顾一下这两件事。
Rust Foundation在今年提出了一项关于Rust 商标政策的修改建议,这引发了社区的广泛关注和讨论。这项修改建议主要涉及对“Rust”这个词和其Logo的使用规定,包括建议人们在他们的Rust crate名称中不要使用“Rust”,例如,建议使用 vulture-rs
而不是vulture-rust
。这些草案的变动引发了社区的反弹。
在咨询期间,Rust社区的许多人对政策草案及其监管团体提出了问题、关注和困惑。Rust Foundation在声明中表示,他们理解制定Rust商标政策的过程应该更加透明,并为此道歉。社区的反应甚至导致了一部分人以“Crab”(螃蟹)的名义对Rust语言进行了分支(crablang),以抗议预期的对侵犯组织的Rust和Cargo商标使用的打压。(这个 crablang 分支仅仅是为了表达抗议,结果被国内很多技术媒体解读为 Rust 语言分叉。真正想分叉 Rust 语言,不仅仅需要技术人才,还需要大量资金才做得到,而不是仅仅在 GitHub 上 fork Rust 开源仓库)。
之后,Rust Foundation试图通过一份声明来缓解这场争议,他们承认草案并不完美,并表示他们承诺修正任何被指出的错误,并考虑我们收到的反馈。他们还注意到,他们看到了“针对基金会员工的大量骚扰和滥用”,并表示他们将执行Rust项目的行为准则以保护这些人。
Rust的创造者 Graydon Hoare 在 Reddit 的一个讨论线程中对社区的反对意见表示了支持。他写道,新的政策让所有人都停止使用名字和Logo,这是社区成员多年来一直在做的事情,而旧的政策是允许他们这样做的。
Rust Foundation在之后声明中表示,他们将考虑社区的反馈,以制定进一步的草案。他们表示,政策制定过程的咨询阶段旨在给Rust社区成员提供一个机会,让他们能够审查商标政策的初稿,并表达他们的问题、关注和评论。这个过程帮助他们理解,初稿显然需要改进。在下一阶段,他们将提供更多的进展更新,并努力解决被提出的问题。虽然他们对反馈的审查刚刚开始,但已经很明显,对初稿的许多批评是有效的,他们将在政策的下一个版本中解决这些批评。
这件事引发争议的可能原因是,大家对新商标法的理解产生了混淆,这一点 Rust 语言库团队 leader mara给出了解释: 发布有关Rust的内容是可以的,但是一家公司不能未经许可就称某物为“Rust 语言规范”。
“社区有人打趣:简而言之,这是关于 Rust 商标所有权的问题,允许引用,但必须通过借用检查器。
当然,Rust 基金会的出发点是好的,但需要在社区和法律之间寻找一个平衡点。期待一个合理的商标政策。
事件背景:
ThePhD 是一个知名的 Rust 社区成员,他被邀请在 2023 年的 RustConf Keynote 上发表演讲。然而,他的演讲在会议开始前的最后一刻被降级为一个普通的会议议程。
引发争议的原因:
ThePhD 一直在为一项实验性语言功能(Rust 语言编译期反射)制定提案,这项工作得到了Rust基金会的赞助。
今年,他的工作引起了 RustConf 组织者的注意,他们邀请了作者在 2023年的 RustConf 上发表主题(Keynote)演讲,显然是由"Rust项目领导层" 投票选出的。
作者选择将上述提出的语言特性作为他们演讲的主题,并向RustConf的组织者多次声明了他的工作还没有 RFC/Pre-RFC ,可能会让听众产生误会,以为 Rust 语言团队要支持编译期反射了。但是Rust项目领导都明确表示可以作为主题演讲。
在此之后的某个时间点,RustConf的组织者联系了作者,告知他们的演讲从主题演讲降级为普通演讲,显然是在Rust项目领导层的要求下进行的。他们不希望给人们留下实验性提案(甚至还没有成为预备RFC的阶段)是语言官方方向的印象,并且显然担心将其作为主题演讲会给人们留下这样的印象。
结果,作者(ThePhd)完全退出了 RustConf 演讲。
事件影响:
这个决定引发了 Rust 社区的广泛讨论。
首先,作为邀请 ThePhd 作为主题演讲的 RustConf 组织人员 JT 发文宣布《为什么我离开 Rust 》。因为他认为这是 Rust 组织对领域专家的一次羞辱,让他感到极度不适。他 感受到 JeanHeyd (ThePhd)被羞辱时的痛苦和失望,心碎了。最关键的是, ThePhd 是一名黑人,这种先给予尊重然后再剥夺的降级对他而言是非常敏感的。(需要说明的是 JT 只是退出 RustConf 相关组织)
很多人可能难以理解 Keynote 主题演讲在美国的重要性。作为 Keynote 演讲除了是一份荣誉之外,还对找到一份非常不错的工作提供了极佳的机会。但是 ThePhd 的生气应该不是因为失去这种职业机会,他本身就是非常优秀的 C 语言工程师。他生气是因为自己没有得到应有的尊重,被 Rust 组织中某个人利用自己的职权之便,对他的 Keynote 演讲资格进行了「私人审判」。因为降级的过程并没有得到全体领导层投票,只是某人的一个私人决定,所以他的质疑是合理的,这可能是因为歧视黑人或者是 Rust 官方团队对他的主题内容相关工作不认可但没有明确传递给他。
“做个类比。他们说:“嘿,thePHD,你在我们的新电影中得到了主演角色...哦,实际上...开玩笑的,你是那个呆萌的配角。”
此事经过激烈的社区讨论之后,库团队 Leader mara 再次就 ThePhd 这件事发布声明,她提到了事情的真相:在领导层决策过程中,他们没有做到检查和确认这些主题演讲的责任,而错误传递 ThePhd 是主题演讲的信息,等日程表最终确定以后,ThePhd 被私下告知了这个变动,当然无法接受。
后续行动:
Rust 官方发文对 ThePhd 主题演讲降级事件进行了公开道歉,并且承认事件的主要原因是领导对话的决策和沟通过程有问题,这是组织和流程上的失败。
为了改进开源社区治理,避免此类问题再次发生,官方宣布成立Rust 领导委员会(Leadership Council) ,这是 Rust 项目的顶级治理机构,由 RFC 3392 发起提案。该领导委员会将负责最高级别的治理问题,而Rust项目的大部分责任(如编译器和核心工具的维护、语言和标准库的演进、基础设施的管理等)仍由九个高级团队承担。
有人说,这些事件对于 Rust 组织来说是一个有趣的“成长”时期。我很认同这个看法。Rust 语言开源社区的发展并没有一个成熟的前车之鉴或榜样可以借鉴,只能在犯错中成长,良好的开源社区治理不会偶然发生。
但我们也不能忽略每次犯错所付出的代价。
ThePhd 在经历此事之后,完全终止了他对于 Rust 编译期反射的工作。这是非常令人失望的。如果你看过 ThePhd 对于编译期反射的工作报告,你会认可他工作对 Rust 语言的价值。这是 Rust 语言的损失。我不知道 Rust 官方如何弥补这个损失。
也许未来 Rust 的某个版本会支持编译期反射,但这次事件无疑让这个非常有价值的语言特性延后了。
哪里有人类,哪里就有政治。
由于 Rust 没有明确的“所有者”,而是以更加开源、分散和公开的方式进行开发,这些失误非常明显(当然,这也有助于人们试图更好地构建“社区”的普遍态度)。所以,Rust 具有更复杂的社会性,可能会引发更多冲突。这也是成立 Rust 领导委员会的必要性。
“You don't have to be perfect. These are the values which we think make the Rust community better. But it doesn't mean that you need to make the community better in every possible way, your personal happiness is more important. If you feel that some of these values don't align perfectly with the way you prefer to work, that's fine, as long as you follow the code of conduct.
Rust 社区的 Matklad 说的非常好:“你不必完美。这些是我们认为能够让Rust社区变得更好的价值观。但这并不意味着你需要在各个方面都让社区变得更好,你个人的幸福更重要。如果你觉得其中一些价值观与你偏好的工作方式不完全一致,那也没关系,只要你遵守行为准则即可”。
但现在看来,不仅仅是遵守行为准则这么简单就能治理好开源社区。
作为 Rust 开源社区的普通一员,我只能祝愿 Rust 语言和社区能顺利发展下去。
“社区的人们总喜欢关注八卦,有几个人正在关心 ThePhd 这项工作的内容呢?
ThePHD 研究的 Rust 编译期反射 对 Rust 语言非常有价值。这里做一个简单的解读,以后有时间再深入。当然目前该工作应该已经停滞,并且也从来未曾得到 Rust 项目官方团队的认可,因为还没有机会去发 pre-RFC 讨论。
这篇文章主要探讨了在 Rust 中实现编译时反射的可能性。作者首先说明 Rust 目前并没有真正的编译时反射功能,常见的像 rocket.rs 这样的宏只是利用了proc macro 在预处理阶段生成代码的手段,而 proc macro 完全依赖于第三方库 syn 。
目前社区里依赖 Any
trait 实现的运行时内省功能(比如 bevy_reflect),则不是零成本抽象的。
作者认为Rust当前的 trait 系统有以下局限:
孤儿规则(Orphan Rule)限制了外部 crate 类型的 trait 实现,导致需要大量 wrapper 和特殊类型来实现一些通用功能
trait 无法表达对字段的完整约束,无法进行编译时遍历和计算
缺少变长参数功能,无法处理异构(heterogenous)集合
元组访问需要硬编码索引,无法进行编译时编程
使用 访问者(visitor)模式进行遍历也需要维护状态,导致代码不优雅
为此,作者提出在引入语言级编译期内省的功能( 通过在 std::introwospect
和 core::introwospect
模块 API )来试图解决这些问题:
introwospect_type
: 反射类型信息
introwospect
: 反射调用 visitor
introwospect_over
: 遍历调用 visitor
但是这些关键字都需要编译器的支持,在当前版本的Rust 中无法实现。
作者认为 Rust 的 trait 系统在表达编译时反射方面还有不足,需要 const 泛型表达式等功能的加强。他们计划继续探索这一方向,为 Rust 提供更优雅的编译时反射功能。
总的来说,文章深入探讨了 Rust 的泛型编程现状,分析了实现编译时反射的需求和潜在问题,为 Rust 的类型系统提供了很好的反馈和建议。
“好可惜,希望后续有人能接手这份工作,当然希望 ThePhd 可以继续完成它。
截止 2023 年 8 月,crates.io 上面 crates 下载量为 400多亿次,一共有超过 12 万(121,520)个crates。
crates.io 巨大的下载流量也是 Rust 官方一个巨大的负担,为了改进这个状况, Rust 官方现在修改新索引协议,从Rust 1.68版本开始提供。新的索引协议为“稀疏(sparse)”协议在访问crates.io时通常会显著提高性能。新协议不再使用git,而是直接通过HTTPS从索引中获取文件。Cargo只会下载与开发者项目中特定包依赖相关的信息。
以下会罗列一些较为知名的库和框架,仅供参考。Rust 生态目前非常丰富,没有罗列出来的不等于它就不知名不常用。
rust-analyzer,无疑是大家最喜爱且 Rust 开发必备的工具。跟它竞争的工具有:
intellij-rust ,用于 Intellij
rust.vim,用于配制 Vim
rust-mode,用于配置 Emacs
Clippy,用于提升你代码质量的必备工具。配套工具 rustfmt。
PyO3,流行的 Python 解释器的 Rust 绑定库,Rust 在人工智能领域开疆破土必备工具。
neon,流行的方便编写安全的 Node.js 模块的 Rust 绑定库。
Rustler,流行的方便编写安全 Erlang NLF 函数的 Rust 绑定库。
cbindgen,流行的自动为 Rust 代码创建 C 绑定的库。
cxx,用于从 Rust 安全调用 C++ 代码,以及从 C++ 安全调用 Rust 代码,不受使用 bindgen 或 cbindgen 生成unsafe 的 C风格绑定时可能出现的许多问题的影响。
rust-bindgen,流行的为 C(部分 Cpp)库自动创建 Rust 绑定的库。
tarpaulin,Rust 代码覆盖率统计工具。竞品有:
quickcheck
afl.rs
Proptest,是一个受Python的Hypothesis框架启发的属性测试框架(即QuickCheck家族)
serde,最流行的序列化反序列化工具。编码类工具还有:
bincode,二进制序列化反序列化
byteorder,大小端字节序
json,JSON 序列化反序列化
html5ever,高性能 HTML5 解析器
msgpack-rust,MessagePack 的 Rust 实现
prost,ProtocolBuffer 的 Rust 实现
Rust 语言网络和 Web 后端框架我将其分类有四大派系:async-std 系、 tokio 系、大厂自研系和WebAssmbly Server Side 系。
tokio 系:
tokio,算是目前 Rust 异步生态事实性的通用 Rust 异步运行时
hyper,流行的 Rust HTTP 库
reqwest,流行的 Rust HTTP 客户端
actix-web,流行的 Web 异步开发框架,同类型竞品有:
axum,基于Tokio、tower
和Hyper构建的模块化的Web框架,注重人机工效学。
poem,一个功能齐全且易于使用的基于Rust编程语言的Web框架。
rocket,一个注重易用性、安全性、可扩展性和性能的异步 Web 框架。
tonic
,gRPC的Rust实现,是一个高性能、开源的通用RPC框架,专注于移动和HTTP/2。
async-std 系:
async-std,是由 Rust 官方团队维护开发的异步标准库。虽然应用不如 tokio 广泛,但目前还在维护中。
tide,是官方维护的异步 Web 框架,目前在缓慢维护中。如果上生产,还是建议使用 tokio 系框架。
大厂自研系:
ylong_runtime,由华为自研的 Rust 异步运行时,优势是针对于 mobile 做了特别优化。
monoio,由字节跳动自研的基于 Linux io-uring 的 Rust 异步运行时。
volo,用于构建微服务的高性能和强可扩展性的Rust RPC框架。
tarpc,非 Google 官方但是在 Google 官方仓库里的 gRPC Rust 框架。
WebAssmbly Server Side 系:
lunatic[1],是受 Erlang 影响的一个 WebAssembly 运行时。你可以使用它快速、健壮和可扩展的服务器端应用程序,但是你可以通过任意可以编译为 WebAssembly 的语言来使用它。在今年(2023)的 WASM I/O 会议上,有人分享了如何使用 Lunatic来构建高并发应用。
submillisecond 是 lunatic 在去年推出的一个 Web 框架。注重 WebAssembly 安全性,基于 lunatic 调度运行时。submillisecond 的另一个特色是支持 Liveview 。Liveview 的灵感来自于Elixir的Phoenix web 框架 。LiveView 编程模型是声明式的:LiveView 中的事件不是说“一旦事件 X 发生,就在页面上更改 Y”,而是可能导致其状态发生变化的常规消息。一旦状态发生变化,LiveView 将重新渲染其 HTML 模板的相关部分并将其推送到浏览器,浏览器以最有效的方式进行自我更新。这意味着开发人员像编写任何其他服务器呈现的 HTML 一样编写 LiveView 模板,LiveView 负责跟踪更改并将相关差异发送到浏览器。
spin 是 fermyon 团队开源的一款用于使用 WebAssembly 构建和运行快速、安全且可组合的云微服务的框架。它旨在成为开始使用 WebAssembly 微服务的最简单方法,并利用 WebAssembly 组件模型 和Wasmtime运行时的最新发展。今年已经发布 1.0 ,旨在简化 WebAssembly 微服务。并提供了 Fermyon Cloud 服务,方便开发者快速部署 spin 应用。
Rust 也涌现了不少大前端应用开发框架和库, 2023 年还在持续增长的有:
Deno 是一个现代且安全的 TypeScritp 和 JavaScript 运行时,基于 V8 和 Rust 实现。Promises
、async/await
、ES模块
和异步迭代器
等在Deno中都是一等公民。2023 年 Deno 发布了 Deno Deploy 服务,这是deno官方提供的一个分布式部署环境,它可以让你的代码快速部署到全球34个节点,你可以不需要配置,不需要维护就快速部署好你的应用。Deno 今年正向Deno 2 的重大版本迈进。
swc,是 Speedy Web Compiler 缩写,是一款用 Rust 编写的超快 TypeScript / JavaScript 编译器。版本依旧非常活跃地更新着。2023 年该项目作者 dudykr 又开了一个新坑 stc,是一个高性能的 TypeScript 类型检查器,虽然引来一些争议,但他还是一直在开发中。
parcel ,是一个 Rust 实现的 Web 应用打包工具,适用于经验不同的开发者。它利用多核处理提供了极快的速度,并且不需要任何配置。它基于 swc 实现。2023 年 parcel 发布了 v2.9.0 版本,该版本用 Rust 重写了依赖文件路径 resolver。parcel 还开源了一个新的 CSS 解析、转换和压缩工具 parcel-css 。
Yew 是一个设计先进的 Rust 框架,目的是使用 WebAssembly 来创建多线程的前端 web 应用。它基于组件,灵感来自于 React 和 Elm,高性能,且支持与 JavaScript 交互。目前还在活跃开发中。
sycamore 是一个响应式的无虚拟dom 的 前端库,同样是基于 Rust 和 WebAssembly 。它的特点是,不支持 JavaScript ,因为不需要。
Turbo 是一个用Rust编写的前端开发的下一代工具链,由三个部分组成:
Turbopack: ,一种增量打包工具(Webpack的继任者)
Turborepo: ,一个增量构建系统
Turbo engine,一种底层增量计算和记忆化引擎
嵌入式安全操作系统 TockOS 2.1 发布 。在 TockOS 迈向 2.0 时,许多核心的内核API被重新设计和重写。并且支持11个新的硬件平台,包括 RISC-V。TockOS 的贡献者之一 Alexandru ,创办了 OxidOS 公司,为汽车软件OEM和开发商提供安全操作系统和开发工具。
在今年(2023)首届嵌入式开源峰会(EOSS)上,由瑞士的Zühlke Engineering 公司嵌入式工程师 Mosler 分享了 《Fearless Embedded Rust》,他和他的公司都看到了Rust在嵌入式项目中的潜力。
他在演讲现场展示了使用乐鑫官方推出的物联网开发框架 esp-idf 开发了一个物联网温度检测器。他用了 ESP32-C3开发套件,采用了RISC-V架构,并且具备Wifi功能。他的 fearless-embedded-rust 代码在GitHub 仓库。
他展示的重点是 Rust 工具链在物联网嵌入式开发领域提供了生产级可用的开发工具链和生态框架,方便构建开发环境,而 Rust 语言现代化的安全的类型系统和所有权语义也可以帮助嵌入式开发者构建更健壮的嵌入式应用。比如 Rust的所有权模型直接映射到保留外设。也就是说,当你请求某个外设时,其他代码将无法访问它,这由编译器本身强制执行。
嵌入式生态库日益丰富:
embedded-hal,嵌入式系统的硬件抽象层(HAL),作为构建跨平台驱动程序生态系统的基础。该库已经马上要发布 1.0 了。嵌入式开发的人都知道依赖关系不协调的痛苦,这个抽象层就是为了解决这个问题,它本质是跨平台抽象。
Knurling, 是 Ferrous Systems 的一个项目,为了改进嵌入式 Rust 的体验,提供了一系列开发工具:
probe-run
,允许开发者利用 Cargo 像本地应用程序一样快速运行和运行嵌入式应用程序。
defmt
,针对资源受限设备(如微控制器)的高效日志框架。 defmt
代表“延迟格式化”,可以将格式化操作推迟到将输出日志的主机上进行。
flip-link
,为嵌入式程序提供零成本的栈溢出保护。目前只支持 Arm Cortex-M 微控制器。
embassy ,在嵌入式中,通常使用中断、DMA 并利用多核来处理并发事件而不阻塞主循环。这些传统上是通过有意的寄存器写入来处理的。例如,向外围设备发送命令以启动任务,继续运行程序,当任务完成时,会触发一个中断,并立即运行处理完成的代码。Rust 中可以使用基于 Future 的 Async/Await 功能来抽象这些过程。
embassy-stm32,适用于所有STM32微控制器系列。
embassy-nrf,适用于北欧半导体(Nordic Semiconductor)nRF52、nRF53、nRF91系列。
embassy-rp,适用于树莓派RP2040微控制器。
esp-rs,适用于Espressif Systems ESP32系列芯片。
Embassy HAL 支持在 esp-rs/esp-hal 库中,ESP32 微控制器的 no_std Rust 硬件抽象层(Hardware Abstraction Layers),这是乐鑫公司官方的库。。
异步 Wifi、蓝牙和 ESP-NOW 在 esp-rs/esp-wifi 库中。
esp-idf,是乐鑫官方推出的物联网开发框架,支持 Windows、Linux 和 macOS 操作系统。
rustsbi,RISC-V Supervisor Binary Interface (SBI)库。可在M模式或HS模式下运行。
为什么嵌入式软件领域目前还没有转向 Rust 呢 ?
目前有一些阻碍 Rust 成为嵌入式软件主流编程语言的重要因素:
硬件供应商的支持。大多数芯片供应商只支持 C 或C++ 的硬件抽象层(HAL)、驱动程序和使用示例,而Rust作为一个相对较新且用户群体相对较小的语言,他们为什么要承担支持Rust的工作呢?Rust嵌入式生态系统主要由社区编写的开源软件组成,公司开发从依赖硬件供应商转到依赖开源生态需要转变态度。好消息是,对于 Rust 的供应商支持正在逐渐完善。在过去几年中,Infineon (是首家支持Rust编程语言的主要半导体制造商,首批支持的产品包括AURIX TC3xx和TRAVEO T2G汽车MCUs) ,以及 Espressif (乐鑫)都开始为Rust开发软件开发工具和工具包。
芯片支持。Rust嵌入式生态系统在对某些芯片的完整性甚至可用性方面存在很大差异。Rust 没有 C 语言几乎支持任何架构的优势,但即使 Rust 支持微控制器的架构,可能也没有相应的 HAL 可用,或者可能是不完整的。尤其是较新的芯片更容易受到这个问题的影响。当然,这种情况也在好转,很多公司愿意为开源贡献生态缺失的 HAL,比如 Tweede golf 公司。
Rust 开发者缺乏。这是一个“鸡生蛋还是蛋生鸡”的循环引用问题。很多公司能预见到 Rust 潜力,并且相信公司未来会转到 Rust ,但是,因为很难找到擅长Rust的开发人员,所以这个转型进程就一直拖延着。然而,如果几乎所有嵌入式开发工作都是给 C 或 C++ 开发人员的,开发人员为什么要投入大量时间学习Rust 呢?所以,需要打破这种“鸡和蛋”的循环才行。
RTOS vs Embedded Async
多年来,实时多任务操作系统 (RTOS) 一直是嵌入式应用软件的基础和开发平台。而 Rust 带给嵌入式开发的现代化的开发特性是异步编程,有希望可以更好地替代 RTOS。
Tweede Golf团队对这两者进行了对比,嵌入式 Rust 使用了嵌入式异步运行时 Embassy。Embassy 可能是嵌入式系统中最受欢迎的异步执行器它还为许多热门的微控制器提供了完全实现的硬件抽象层(HAL)。
异步 Rust 的最大好处之一是更小的 RAM 占用。传统的实时操作系统(RTOS)需要为每个任务分配一个堆栈。Rust 的 futures 只需要跟踪在 await 点之间使用的变量。这意味着异步任务所需的内存可以比传统的 RTOS 任务小得多,对于较简单的任务,甚至可以只有几十个字节!这意味着异步可以启动更多具有较小离散工作的任务,而不是将多个职责过载到单个任务中。
另一个好处是任务之间没有上下文切换。由于在一个协作调度的环境中运行,当任务处于挂起状态时,不需要保存和恢复任务的状态。这意味着异步可以花更多时间做有用的工作,而不是上下文切换!
当然异步也有它的缺陷,异步不方便调试,栈展开并不完全符合预期。另一个不足是协作调度的方式没有优先级,但是可以通过使用中断自己的优先级,每个中断都会运行一个执行器。这种方式实现了基于优先级的调度,但与传统的抢占式实时操作系统相比,增加了相当多的复杂性。
异步 Rust 是嵌入式系统的强大工具,使开发者能够编写易于理解且占用内存较小的并发代码。尽管它也有一些缺点,但在我看来,其优势远远超过了成本。
Rust 生态中也有很多图形处理和 UI 框架,在往年的盘点中也介绍了不少。本文挑选一些重点项目来看看它们今年的进展。
wgpu 适用于GPU上的通用图形和计算。使用wgpu的应用程序可以在Vulkan、Metal、D3D12, D3D11, 和OpenGL ES上原生运行;在 wasm 上使用 WebGPU。该API基于WebGPU标准。它是Firefox、Servo和Deno中WebGPU集成的核心。
gfx-rs 团队在 2023 年没有公开什么动态,但是从代码仓库的 Changelog 看,团队一直在积极更新。
EmbarkStudios 公司开源的 rust-gpu 今年发布了 0.9 版本。虽然该项目目前许多东西还没有实现,还远远没有达到可以投入生产的程度,但是该项目的前景是相当不错的。在游戏中,GPU编程以往都是通过编写HLSL或在较小程度上编写GLSL完成的。这些都是简单的编程语言。然而,随着游戏引擎的发展,这些语言未能提供处理大型代码库的机制。Embark 凭借拥有优秀的渲染工程师团队,希望通过将现有的、低级别的、安全的、高性能的 Rust 语言带到GPU上,来推动这个行业的发展。而随之而来的是一些不可忽视的额外好处:一个业界最好的包/模块系统,针对竞赛条件或越界内存访问的内置安全,广泛的工具和实用程序,以改善程序员的工作流程,以及其他许多东西。
rust-gpu 项目为 rustc编译器后端生成SPIR-V,通过-Z codegen-backend
插入。这与rustc_codegen_cranelift
和rustc_codegen_gcc
使用的机制相同。目前只计划支持SPIR-V,Vulkan的开放编译器目标。未来的版本可能会支持DXIL(DirectX的目标)或WGSL(WebGPU的着色语言,与SPIR-V是双投影的)。
Bevy 是一个用Rust构建的简单得令人耳目一新的数据驱动的游戏引擎。拥有现代化且可扩展的2D和3D渲染器,一流的ECS(实体组件系统)令人愉悦地使用,拥有丰富的功能,并且拥有充满活力和开放的开发者社区。目前,它支持Windows、MacOS、Linux、iOS和Web。我们还在进行Android支持的工作……并且未来还有更多平台的雄心壮志!
bevy 在 2023 年截止目前,发布了 0.11 版本,其中有一些重要更新:
WebGPU 支持:Bevy现在可以使用现代的WebGPU Web API在Web上更快地渲染,并具备更多功能
即时模式Gizmo渲染:轻松高效地渲染2D和3D形状,用于调试和编辑器场景
ECS API:Schedule-First ECS APIs 和 ECS Audio APIs
网格UI布局:Bevy UI现在支持CSS风格的网格布局
改进的着色器导入:Bevy着色器现在支持细粒度导入和其他新功能
ECS Schedule v3:Bevy现在具有更简单、更灵活的调度功能
环境贴图照明:360度环境图像照明,可以以低成本且显著地提高场景的视觉质量。
改进的Android支持:Bevy现在可以在更多的Android设备上直接使用(有一些注意事项)
ECS 优化:同样地,我们对许多常见的 ECS 操作进行了加速。Bevy 应用程序将获得良好的速度提升!
pixels 一个轻量的硬件加速的像素帧缓冲器。使用 pixels 可以迅速为一个简单的2D游戏、基于像素的动画、软件渲染器或你最喜欢的平台的仿真器制作原型。建立在由wgpu驱动的现代图形API上:Vulkan、Metal、DirectX 12、OpenGL ES3。对DirectX 11、WebGL2和WebGPU的支持还在进行中。
Graphite 是一个 Rust 实现的轻量级的光栅和矢量 2D 图形编辑器,它是免费和开源的,可以用于浏览器中。它的目标是重新定义图形编辑。在今年 2023 年全球进入 AI 时代的潮流之下,它也选择加入了 AI 功能。它的初级基于节点的合成器可以让开发者应用光栅效果,并与人工智能共同创作令人惊叹的艺术作品,而且工作流程是非破坏性的。目前,正在全力开发功能齐全的光栅图像编辑和本地桌面应用程序,并将在未来几个月内推出。
lyon 一个用 Rust 编写的路径细分库,用于基于 GPU 的 2D 图形渲染。目前lyon 正式发布 1.0 版本。lyon 从 2016 年开始开发,之所以迟迟发布 1.0 ,是因为作者希望 lyon 成长为一个功能齐全的 2D 渲染器。在达成这个目标的过程中,作者发现开发一个快速而健壮的曲面细分器本身就是一个大项目,所以就有了现在的 1.0 。2023 年 lyon 缓慢维护着,作者受 zig 语言影响开始钻研 Rust 中如何实现自定义分配器,并且在 lyon 的 tessellator 中尝试。
图计算
阿里巴巴 GraphScope 交互式引擎(GIE),是一个分布式系统,专门设计用于方便各种用户以探索性的方式分析大型复杂图结构。它利用Gremlin提供高级语言进行交互式图查询,并提供自动并行执行。其中 查询 executor 使用 Rust 开发,极大地增强了其性能。
分布式流处理引擎
arroyo,与Apache Flink 流处理工具竞争的 Rust 流处理引擎,Arroyo 官方声称比 Flink 性能快 10 倍。可用于实时的数据处理。
深度学习框架
burn 是一个新的深度学习框架,支持CPU和GPU,使用新的 Rust 特性 GAT 功能来支持多个后端作为插件。
“作者如是说:“总的来说,我一开始并没有 GAT,但我很快意识到有它比没有它要容易得多。”
这个库旨在成为一个用 Rust 编写的具有极高灵活性的且完整的深度学习框架。目标将是满足研究人员和从业者,使实验、训练和部署您的模型更容易。
用Rust编写的其他机器学习框架要么限制性太强(比如要求在编译时就知道矩阵的大小),要么API不够理想,要么缺少关键的功能,比如GPU支持。Burn 不一样,Burn 基于 Backend
trait 架构来支持不同的后端。Burn 的目标是使创建优化的后端非常容易,并支持不同的设备和使用情况。目前,只有3个后端。NdArray是一个纯粹的Rust解决方案,Tch是一个易于访问CUDA和cuDNN优化的操作,ADBackendDecorator使任何后端都可以区分。Burn 现在正在重构内部的后端API,使其尽可能容易插入新的API。
2023 年 burn 又支持了新的 GPU 后端,利用 wgpu 自动支持Vulkan、OpenGL、Metal、Direct X11/12 和 WebGPU。
Rust 与大语言模型
llm-crabllama2-burn,又将 Meta 最新发布的开源大型语言模型Llama2移植到Rust深度学习框架 Burn 上。这个项目也引起了 Graphite 图形编辑器团队的注意。
“Graphite 团队表示,对 Python 的不可移植性感到相当沮丧。拥有一个纯Rust实现将是一个很好的解决方案(而Burn 甚至比 tch-rs 更纯粹,后者是对PyTorch C++ API进行FFI绑定)。对于我的使用情况来说,可移植性和纯Rust非常重要...
Graphite 团队表示将开始为 Stable Diffusion 迁移到 Rust 实现,除了原始论文之外,还有数十个额外的功能,这些功能增加了有用的能力(ControlNet、嵌入、Dreambooth、LoRA、不同的模型版本、xformers等),将它们移植到Rust需要一些努力。由于我目前在Graphite开源团队担任产品经理的职务,我也可以担任一个团队的产品经理,负责Stable Diffusion的移植工作,以实现与最先进的Python发行版(如AUTOMATIC1111)完全功能相同的移植,以协调对Rust开源生态系统、Burn和Graphite的利益有益的团队的努力。可能从小规模开始(如MiDaS、ESRGAN等),然后逐渐转向Segment Anything,再稍后移植Stable Diffusion,以便团队积累一些经验。
llm,是一个用于处理大型语言模型的 Rust 库生态系统 - 它是基于快速高效的 GGML 机器学习库构建的。llm
由 ggml
张量库提供支持,旨在将Rust的稳健性和易用性带入大型语言模型的世界。目前,推理仅在CPU上进行,但后续希望通过备用后端在将来支持GPU推理。
Chidori 是一个 LangChain 的替代品,同样可以方便的构建AI Agent,主要优势是反应式编程。由 Rust 开发,能支持Python、Nodejs和Rust构建Agent。它目前处于 alpha 阶段,尚未准备好投入生产使用。以下是它的一些特点:
从头开始构建代理
运行时由 Rust 编写,开箱即支持 Python 和 Node.js
构建可实际运行的代理
LLM 缓存可最大限度地降低开发成本
针对长时间运行的人工智能工作流进行了优化
嵌入式代码解释器
支持时间旅行调试
qdrant,是 Rust 实现的一个开源向量数据库。向量数据库作为大语言模型的「长期记忆」能力,当下很火。qdrant 目前融资 750 万美元种子轮。而在向量数据库业内的独角兽公司 Pinecone 用 Rust 重写数据库之后,B 轮融资 1 亿美元。传统数据库可以通过添加向量存储和向量搜索来提供向量数据库的功能,但是面对海量数据量,想要平衡向量搜索的准确度和性能,还需要专门的向量数据库。Qdrant (商业开源)和 Pinecone (商业闭源)就是专业的向量数据库。从 Qdrant 的实现看出,其在向量内存占用优化和向量海量搜索算法上下了不少功夫。内存占用优化使用Product Quantization(乘积量化) 技术,使用 K-Means 聚类算法来平衡准确性和搜索性能。
async-openai 是 OpenAI REST API 的非官方 Rust 绑定,基于 OpenAPI 规范 。当API 服务器限制速率时,将使用指数退避重试非流式请求。
Mithril Security 公司开源了BlindAI,这是一种用于机密推理的开源 AI 部署解决方案。如今,大多数 AI 工具的设计机制都没有提供隐私保护,因此当数据被发送给第三方进行分析时,数据可能会遭到恶意使用或可能泄露。与常规 AI 推理解决方案一样,BlindAI 帮助 AI 工程师为最终用户提供模型以从他们的预测中受益,但增加了隐私层。用户发送给 AI 模型的数据从传输到分析始终保密。这样,用户就可以从 AI 模型中受益,而无需向任何人公开他们的数据:AI 服务提供商和云提供商(如果有)都看不到这些数据。
tokenizers 是 Hugging Face 公司开源的一款 Rust 实现的分词库。基于深度学习的现代 NLP 管道中的瓶颈之一就是tokenization,尤其是通用性强且独立于框架的实现。所以,该分词器的核心是用Rust编写的,并且存在Node和Python的绑定。提供当今最常用的分词器的实现,重点是性能和通用性。
faer-rs 是一个用 Rust 实现的线性代数例程的 crates 集合。目标是为线性代数提供一个功能齐全的库,重点关注可移植性、正确性和性能。目前还在活跃开发中。
在往年的 Rust 生态报告中我也罗列了不少 Rust 在云原生方向的开源应用,今年主要关注下 WebAssembly 在云原生的进展,因为 2022 年底由CNCF wasmCloud的联合创始人兼Cosmonic的首席执行官 Liam Randall 预测,2023 年云原生开发将由 WebAssembly 引起巨大变革。
今年 4 月在阿姆斯特丹举办的 KubeCon 欧洲大会,对 WebAssembly 总体趋势有一些反映:
WebAssembly 组件模型提供了语言支持、互操作性以及在编写软件方面的巨大潜力。与仅仅一年前组件模型还是一个新概念相比,我们现在已经看到了组件模型的演示。
Serverless 是 WebAssembly 一个重要应用领域。
Wasm非常适合插件系统,比如 vst-rs,附加关于 WASM 作为通用插件系统相关文章。
Docker 正在努力支持尽可能多的Wasm运行时,目前的列表包括:spin, slight, Wasmtime, 和 WasmEdge。
k8s 支持 wasm 构建微服务,比如 spin 支持 k8s 。
WebAssembly(Wasm) Server Side 的趋势
目前 WebAssembly(Wasm)生态系统正在发生变革。开发者可以期待一个模块化、可虚拟化和强大的环境,用于构建应用程序、库和服务。
字节码联盟整理了一份 WebAssembly 精简路线图。
wasm-roadmap这个路线图反映了WebAssembly社区组(CG)和W3C的WASI子组中标准的变化,包括WebAssembly核心、WebAssembly组件模型、WASI(WebAssembly系统接口)以及一系列基于WASI的接口。
核心规范概述了构建WebAssembly模块的基础。一些正在进行的重要工作包括:
由Conrad Watt、Andreas Rossberg和Andrew Brown开发的Core Wasm Threads原型,添加了一种新的共享线性内存类型和用于原子内存访问的新操作。
WebAssembly垃圾回收正在由Andreas Rossberg、Ivan Mikushin和Nick Fitzgerald进行研究。
WebAssembly组件模型旨在解决语言互操作性问题,它提供了语言无关的、可组合的、可互操作的、可平台虚拟化的Wasm组件。组件模型在核心规范之上开发,包括WebAssembly接口类型(WIT)IDL。WIT是我们用来描述组件接口的高级类型的语言。
WASI建立在组件模型和核心WebAssembly规范之上。WASI Preview 2将包含至少两个 World 定义,包括CLI-world和HTTP Proxy world。
一些新功能展望:
Rust 语言提供了 Cargo Component ,允许通过 Cargo 命令方便地创建 WebAssembly 组件。
云原生软件的核心构建模块,通过模块化 WASI 接口 将各种云原生接口整合在一起,比如 wasi-keyvalue, wasi-messaging, wasi-sql 和 wasi-blob-store
Rust 非常适合跨平台开发。你可以轻松地编写全面的测试套件,运行时间仅为毫秒级。你可以将其与任何本地 UI 框架结合,并将其部署到 Web(使用WebAssembly)以及iOS和Android(使用FFI)甚至桌面端(macOS/Linux/Windows)。
往年也介绍过一些开源 Rust 的跨平台 UI 库或框架,下面主要介绍一些 2023 年出现的跨平台框架:
Crux 框架,以帮助开发者充分利用 Rust 的表达能力和每个平台的惯用的UX/UI框架。目前为实验性项目。特色是:
它将应用程序分为两个明确的部分:一个由 Rust 构建的核心,尽可能驱动业务逻辑,以及一个由平台本地语言(Swift、Kotlin、TypeScript)构建的 shell,提供与外部世界的所有接口,包括人类用户,并充当核心运行的平台。
两者之间的接口是一个本地的FFI(Foreign Function Interface),具有跨语言类型检查和消息传递语义,简单的数据结构在边界上传递。
架构是事件驱动的,基于事件溯源。核心部分保存了大部分状态,这些状态会根据Shell中发生的事件进行更新。核心部分和Shell之间的接口是基于消息的。
用户界面层是使用现代声明式UI框架(如Swift UI、Jetpack Compose和React/Vue)或基于Web的WASM框架进行本地构建的。用户界面层尽可能地薄,所有其他应用逻辑由共享的核心层执行。
Makepad ,基于 Rust 实现,用于构建本地 UI 和 Web 的框架,目前仅支持Mac和Web平台,未来会支持更多平台。组成:
makepad platform,是Makepad的主要平台抽象层,最大的特色是 Live System,可以在运行时更新Makepad应用程序。另外还包含 Makepad 自定义着色语言 MPSL 。
makepad draw,支持 2D 和 3D (即将支持)绘制。
makepad widgets,包括一个可从DSL设计的保留模式 Widget 系统设计,以及一组基本 Widgets(按钮、滑块、复选框、列表等)。特点是 每个 Widget 都可以确定自己的渲染模型,无论是即时模式、保留模式,还是通常的混合模式。
Makepad Framework,UI 框架,完全在GPU上渲染,并支持一种称为live design的新颖功能。该 UI 框架又由三部分组成:
Makepad Studio,一个具有实时设计感知能力的 IDE 原型,可以检测到DSL代码的更改,而不是Rust代码的更改,从而使应用程序能够自动更新自身。使用Makepad Framework构建。
1Password 也开源了其跨多种语言生成一致的类型模式 的 Typeshare 库。Typeshare 可以帮助开发者实现跨语言无缝同步共享数据类型,这是跨平台安全开发的利器。
在今年的 EOSS 2023 大会中,编译器黑客 Andy 从编译器角度探讨了,现代应用开发框架,包括特定平台的 SwiftUI 和 Jetpack Compose,以及跨平台的 React Native、Flutter 和其他基于 JavaScript 的跨平台框架之间,在编程模型、语言设计和性能之间的关系。
以下是一些关键点:
跨平台应用框架的设计:作者强调了应用开发者和框架开发者之间的分工,应用开发者决定“什么”,框架开发者决定“如何”。这是一种风险的交易,因为框架的设计和实现决定了应用的性能和功能。
框架限制性能的四种主要技术:管理状态、增量渲染、并发渲染和并发垃圾收集(GC)。
Rust 的声明式 UI:作者提到了 Dioxus,这是一个实验性的具有 WebGPU 后端的 Rust 声明式 UI 框架。
WebAssembly 和 WebGPU 的未来:用户应用是 Wasm 模块,它们导入 WebGPU 等功能。WebAssembly 2.0 的 GC 有助于实现高效的互操作性。
作者对 Rust 的跨平台 UI 框架的看法可以从以下几点进行总结:
声明式 UI 已经取得了胜利,这是一个不可逆转的趋势。这意味着未来的 UI 框架,包括 Rust 的跨平台 UI 框架,都会倾向于采用声明式的设计。
框架会限制性能。这是一个需要注意的问题,尤其是在设计跨平台 UI 框架时。因此,Rust 的跨平台 UI 框架需要考虑如何在保证易用性的同时,尽可能地提高性能。
在跨平台应用开发领域,React Native 和 Flutter 是强有力的竞争者。但是,作者认为还有更多的空间可以发展,Rust 的跨平台 UI 框架也有其存在的价值和可能。
作者预测,在未来两年内,Flutter 可能会采用 Rust 作为其实现语言;在未来五年内,可能会出现对 TypeScript 进行静态类型检查的工具。
总的来说,作者认为 Rust 的跨平台 UI 框架有其存在的价值和可能,但是也需要注意到框架可能会带来的性能限制,并需要考虑如何在设计中解决这个问题。同时,也需要关注其他的跨平台应用开发框架,如 React Native 和 Flutter,从中学习和借鉴。
Rust 从 Linux 6.1 进入 Linux 内核开始一路跟随 Linux 内核版本到 6.5,首次将 Rust 语言工具链升级到 Rust 1.68.2。
就在前几天,Miguel Ojeda 发布了升级Rust代码至Rust 1.7.1版本的补丁。从1.68到1.71系列,内核使用的不稳定特性都得到了稳定(唯一允许在 kernel
crate 之外使用的不稳定特性仍然是 new_uninit
)。然而,这次升级确实需要对内核代码进行一些小的更改,主要是为了让 linux kernel crate 中 fork 的上游的 alloc
api 能和上游一致。
今年 3 月份,Asahi Lina 发布了一个基于 Rust 的Apple AGX(M1和M2系列芯片中的GPU)图形处理器驱动程序的初始版本;该发布包含了一定数量的用于图形驱动程序的Rust基础设施。去年 8 月份,Asahi Lina 给 Rust for Linux 邮件组发了一封邮件,陈述了她用 Rust 给 Apple AGX 图形处理器实现 Rust 驱动。
随着 2022 年底 Google Android 团队宣布 Android 13 已经取得了 Rust 内存安全零 Bug 的目标,Google Chromium 项目也在 2023 年 1 月官宣将在 Chromium 项目中支持 Rust 第三方库。
目前 Chromium 团队正在积极地将 Rust 工具链集成到其构建系统中(实际上这项工作已经持续很久了),在明年(2024?)内将 Rust 代码包含在 Chrome 二进制文件中。
为什么选择将 Rust 引入 Chromium?
为了提供一种更简单(无 IPC)和更安全的方式来满足加快开发速度(更少的代码编写,更少的设计文档,更少的安全审查)并提高Chrome的安全性(增加没有内存安全错误的代码行数,降低代码的错误密度)的需求。
Chromium 将如何支持 Rust 的使用?
目前,Chromium 将只支持单一方向的互操作,即从 C++ 到 Rust。Chromium是用C++编写的,大部分的框架技术栈都是C++代码,通过将互操作限制在一个方向,可以控制依赖树的形状。Rust不能依赖C++,所以它不能知道C++的类型和函数,除非通过依赖注入。
暂时只支持 Rust 第三方库。第三方库是作为独立的组件编写的,它们不持有关于Chromium实现的隐含知识。这意味着它们的API更简单,而且专注于它们的单一任务。
Chromium中 Rust 和 C++ 之间的互操作
迄今为止,大多数成功的C/C++和Rust互操作故事都是围绕着通过单一(Narrow)的API(如QUIC或蓝牙的库,Linux驱动程序)或通过明显的隔离组件(如IDL,IPC)进行互操作。Chrome是建立在基础的但真正广泛的C++ API上的,在高层次上,团队发现,由于C++和Rust遵循不同的规则,事情很容易出岔子。例如,Rust通过静态分析来保证时间上的内存安全,静态分析依赖于两个输入:生命期(推断的或明确写入的)和独占的可变性。后者与Chromium的大部分C++的编写方式不兼容,在整个系统中持有冗余的可变指针,以及提供多条路径来到达可变指针的指针。这在Chrome浏览器进程中尤其如此,它包含了一个巨大的(可变)指针互连系统。如果这些C++指针也以复杂或长期的方式被用作 Rust的引用,这就要求C++作者理解Rust的别名规则,并防止违反这些规则的可能性。
总之,如果没有额外的互操作工具支持:
跨语言传递指针/引用是有风险的
语言之间单一(Narrow)的接口对于正确编写代码来说是至关重要的
Google 目前正在投入 Crubit项目,这是一个关于如何提高C++和Rust之间互操作的保真度,并将每种语言的要求表达或封装给对方的实验。
Chromium 团队认为:
““Rust生态系统是非常重要的,特别是对于像Chromium这样以安全为重点的开源项目。这个生态系统是巨大的(crates.io上有96k+的crates),并且在不断增长,包括谷歌在内的整个系统开发行业都在投资。Chrome浏览器在很大程度上依赖于第三方代码,而我们需要跟上第三方投资的步伐。我们必须支持将Rust纳入Chromium项目,这一点至关重要。我们将遵循上述策略来建立规范,并通过第三方程序保持一定程度的API审查,同时我们展望未来的互操作支持,推动Rust和C++之间可能和合理的操作的界限。
内存不安全是整个行业当前面临的问题,而利用 Rust 是在这一领域推进战略的一个部分。
2023 年 5 月,Google 开源了其内部使用的 Rust 供应链安全审计 crate。所有第三方代码都存在一定的风险。在项目开始使用新的包之前,成员通常会进行彻底的审计,以衡量其是否符合安全、正确性、测试等方面的标准。Google 在开源项目中经常使用许多相同的依赖项,这可能导致多个不同的项目对同一个包进行审计时出现重复工作。为了避免重复工作,Google 已经开始在项目之间共享其审计结果。现在,很高兴能够与其他组织一起将它们分享给更广泛的开源社区。
Google 的审计 Rust crate 是 rust-crate-audits ,它依赖于 Mozilla 开源的 Rust 供应链安全工具 cargo vet 。Google 开源的这个 crate 意味着,你可以轻松地将由 Google 员工完成的审计导入到你自己的项目中,以证明许多开源Rust包的属性。然后,凭借这些数据,你可以决定这些包是否符合您项目的安全性、正确性和测试要求。Cargo-vet 对逐步审查您的依赖项有很好的支持,因此很容易引入到现有项目中。
2023 年 6 月,Google 官方又发布了一篇《谷歌在Rust之旅中的5个见解:真相与虚构》,文中揭示了 Google 截止 2022 年内部使用 Rust 的五个见解:
Rust 难学是假象!Rust 语言学习曲线与开发者学习其他编程语言的时间相符,无论是在谷歌内部还是外部。超过2/3的受访者表示在学习Rust后的两个月内,他们有信心为Rust代码库做出贡献。此外,三分之一的受访者在两个月内就能像使用其他编程语言一样高效地使用Rust。在四个月内,这个比例增加到了50%以上。没有看到任何数据表明相对于谷歌开发人员之前使用的任何其他语言,Rust会有任何生产力惩罚。
Rust 编译速度很慢,但是 40% 的开发者是可以接受的。
Unsafe Rust 和 C/Cpp 互操性不是 Goolge 开发人员的最大挑战。目前谷歌开发人员在Rust中面临的三个最具挑战性的领域是:宏、所有权和借用、异步编程。
Rust的编译器错误信息非常出色。只有9%的受访者对Rust的诊断和调试信息的质量不满意。人们对编译器的信息感到惊讶。起初这让人感到意外——人们习惯忽略冗长的编译器错误,但习惯之后,人们喜欢它。
Rust代码质量很高。超过一半的受访者表示,Rust代码非常容易进行审查。作为一名工程经理,这个结果对我来说至少和代码编写结果一样有趣,因为代码审查对于专业软件工程师的角色来说至少同样重要。
所有调查参与者都是在谷歌工作的专业软件开发人员(或相关领域)。虽然其中一些人有过Rust的经验(约13%),但大多数人来自C/C++、Python、Java、Go或Dart。
对于此事,Reddit Rust 频道用户有以下精彩评论:
很高兴看到我的个人经历(轶事)在一个庞大的样本中得到了复制:超过1000名谷歌员工。
在那些“简单、易于编写的语言”中,生产力一直持续到第一次重构,事情停滞不前。而 Rust 在这种情况下则会立即爆发出“闪耀”的生产力。
Rust比Python简单多了。
在我看来,人们经常把高效与忙碌混为一谈。
据说人们只需要不到6个月就能熟练开发 Rust ,但他们也说所有权和借用检查是最大的挑战之一。这告诉我他们实际上并没有真正熟练应用 Rust 。
“神评:没有任何一个内核会逃过 Rust (No kernel will escape)。神回复:一群螃蟹慢慢地朝着远处的一个大苹果爬行(A horde of crabs scuttles slowly towards a large Apple in the distance)
2023 年四月底,微软的操作系统安全和企业副总裁提到了即将到来的关于Windows的变化,涉及到编程语言Rust。
一些重要的变化即将到来,这将使Windows操作系统比现在更加安全。Windows 11 Insider 的用户将首次体验在 Windows 内核中体验到 Rust。微软尽管不断努力让程序员编写更安全的代码,改进底层语言,并采取诸如Windows地址空间布局随机化(ASLR)之类的缓解措施,但缓冲区溢出仍然是一个巨大的问题。彻底根除它们的唯一方法是放弃C和C++,转而使用像Rust这样可以自动管理内存的内存安全语言。
这种方法已经被证明比指望程序员做正确的事情更可靠:在Android中采用内存安全语言,比Windows早几年,已经导致该平台上内存安全漏洞的显著减少。在Windows 11中,将C++替换为Rust的工作已经开始。根据The Register的报道,微软的Windows图形界面设备正在被移植到Rust,涉及约36,000行Rust代码,而Windows内核中目前已经有一个用Rust实现的系统调用(SysCall)。
开发人员现在可以在 Azure Sphere 平台上为联网设备创建应用程序时使用Rust编程语言了。
Azure Sphere 已经包含了用于联网设备的内置安全功能,并且包含基于联发科芯片和基于 Linux 的操作系统构建的硬件。此外,它还包括基于云的 Azure Sphere 安全服务 (AS3),可在设备与互联网或云之间建立安全连接。
AS3 确保安全启动、设备身份验证、软件的信任以及设备运行可信代码的证明。它还使 Microsoft 能够安全地将更新下载到设备上的 Azure Sphere 操作系统和应用程序。将 Rust 引入 Azure Sphere 增加了更多的安全功能。微软在 GitHub 上提供了一个指向 Azure Sphere Rust 项目的链接 ,其中包括 API、示例和许可条款。
作为 Rust 基金会创始白金董事成员之一的华为,目标是引领通信系统软件向安全可信演进,其中 Rust 语言正在发挥很大的作用。华为希望通过部分 C/C++ 代码的迁移,在保证高性能的同时,拥有更高的安全性。
今年华为内部已经开始逐步推广 Rust 语言,引领 Rust 语言在内部广泛落地。同时也将内部的一些 Rust 优秀框架开源出去。今年,在荷兰阿姆斯特丹举办的KubeCon + CloudNativeCon Europe 2023云原生峰会上,CNCF董事、华为首席开源联络官任旭东宣布,云原生多沙箱容器运行时Kuasar正式开源(项目地址:https://github.com/kuasar-io/kuasar)。
今年在 RustChinaConf 2023 大会上,华为也宣布开源了 Rust 异步运行时 应龙(Ylong) 。Ylong 的优势是针对移动领域进行了特别优化,目前在 OpenHarmony 内开源,意味着,OpenHarmony 已经开始采用 Rust 开发了。
另外,在很多国外开源项目和 Rust 大会都能看到 FutureWei 的身影,这也意味着 FutureWei 也对 Rust 生态在大力支持。
在 2022年 7 月,Meta 首次宣布 Rust 成为 Meta 支持服务器端使用的编程语言。到现在 2023 年 8 月为止,从公开的信息可以看得出来,Rust 在 Meta 中的应用主要是为了提升 Meta 内工程师的开发效率。
每天,数千名Meta的开发人员在拥有数百万个文件的代码库中工作。这些开发人员需要在极大规模的工作流程中的每个阶段都能得到帮助的工具。去年 Meta 开源了它们用 Rust 实现的新的源码版本管理工具 Sapling 的客户端,但 Sapling 有三个主要组成部分 :服务器、客户端和虚拟文件系统。
Meta 还用 Rust 开发了新的编译构建工具 Buck2, Meta的许多开发人员使用Buck2来编译结果并测试他们的更改。Buck2被设计为在大规模环境下工作,支持远程缓存和执行,这样开发人员可以共享彼此的编译结果,并且单个开发人员可以访问数千台机器并行运行编译。Buck2还被设计为同时支持多种编程语言。
在**GitHub 新代码搜索背后的技术**一文中,提到 Github 目前的代码搜索引擎基于 Rust 实现。具体来说,是用 Rust 完全从零开始构建一个专门用于代码搜索领域的引擎,代号为 Blackbird。它创建并增量维护一个由 Git blob 对象 ID 分片的代码搜索索引,最终 Blackbird 满足了大家的性能目标:速度非常快,索引也非常紧凑,重量约为(去重)语料库大小的 1/3。
在 GitHub CodeSearch 首页上,展示的代码图片是 rust-lang/rust
项目中的 wtf8.rs
模块。WTF-8(Wobbly Transformation Format − 8-bit)是UTF-8的超集。
Rust 在电商巨头 Shopify 中的应用
Shopify 是加拿大跨国电商公司,在 2022 年 12 月份宣布加入 Rust 基金会,成为基金会第一个金牌会员。Shopify 在服务端一直使用 Ruby 语言,从2021年开始,Shopify 团队开始使用 Rust 实现YJIT,这是一种新的 CRuby 即时 (JIT) 编译器 ,到今年合并到了 Ruby 3.1 版本中。在最近的一次性能测试中,YJIT 的性能比 Ruby 解释器 CRuby 快了 38%。
除此之外, Shopify 也决定采用 Rust 作为公司的系统编程语言,比如编写高性能网络服务器。在 Shopify 看来,Rust 的一致性、性能、社区生态、生产力、安全和互操作性是他们采用 Rust 用于系统编程的原因。
2023 年,Shopify 面向卖家推出了 Shopify Function 功能,卖家可以由此自定义购物车、支付折扣等逻辑。Shopify Function 是基于 Rust 和 WebAssembly 实现的。Rust 在 Shopify 公司的应用主要是为了 WebAssembly for Web Side 服务。
前文提到过,由 Ferrous Systems 公司联合 AdaCore 共同创建的 Ferrocene语言规范(FLS)已经正式发布。该规范主要用于 Ferrous Systems 和 Adacore 合作的项目 Ferrocene,旨在将经过验证的Rust工具链引入安全关键环境。以及 Rust 官方今年准备编写《Rust 语言规范》。
这些都是 Rust 语言广泛应用到高科技和工业领域的前提。
BlackBerry 是将 Rust 语言集成到 BlackBerry QNX 微内核实时操作系统中,Elektrobit 与 BlackBerry QNX 在 Rust 项目上密切合作,贡献代码,确保代码质量,处理项目管理以及与 Rust 社区的互动。Elektrobit 公司是AUTOSAR专家,深耕汽车软件行业,和 BlackBerry QNX 是很多年合作伙伴。
BlackBerry QNX 已在全球范围内获得超过 2.15 亿辆汽车的信赖,并在全球范围内部署在商用车、重型机械和其他市场等一系列行业的嵌入式系统中。其产品已通过多项行业安全标准的预认证,包括 ISO 26262、IEC 61508 和 IEC 62304,该公司还获得德国莱茵 TÜV 独立审计师的认可,成为全球首个通过 ASIL D 安全认证的商业管理程序。
Rust 可与 BlackBerry 经过安全认证的 BlackBerry QNX 产品组合集成,有能力塑造关键任务软件和软件定义车辆的未来
““点评:这次合作比等待 Autosar 直接引入 Rust 的效率高多了。
“关键字:货运自动化列车
自动化货运列车 Parallel Systems,相信货运的未来是铁路,所以研发了零排放的自动化电动货运跑在铁路上,Rust 语言是该公司技术栈的通用语言。该公司也赞助了 RustConf 2022 大会。Parallel Systems 的 GitHub 仓库中有很多 Rust 库,从他们积极维护的 crate 中看得出来它们自动货运列车的 rust 技术栈用在哪里,目测用于传感器数据存储和通信,依赖 stm32 开发板。
dora 是一个基于 Rust 的机器人框架,目标是成为一个低延迟、可组合和分布式的面向 SDV 和 无人驾驶的数据流计算平台。,旨在比当前机器人应用标准 ROS/ROS 2 好 10 倍,成为 ROS/ROS2/Autosar 的替代者。
Rust-os Blog的作者 Philip Opperman是 dora 主力开发者之一 。
dora 通信层暂时依赖于 eclipse-zenoh/zenoh,关于zenoh 的介绍可以参考文章 开源产品 | eclipse zenoh 助力雾计算和边缘计算。dora-rs 的通信层正在被重新设计,目标是将数据面的控制和传输技术分离,比如算子都在一台机器部署的时候,就会用共享内存,这样延时很低。
更多文档参考:https://dora-rs.github.io/dora/
虽然是早期项目,但发展不错,目前正在加入开放原子基金会的过程中,并且在 2023 年基于 dora 开展国际智能驾驶大赛(Openatom Carsmos全球开源自动驾驶算法大赛)。
**h3o 是对 Uber 开源的 h3 地理空间索引系统的纯 Rust 实现,100%覆盖 h3 4.0 API。目标是,在Rust项目中更容易集成,特别是在针对 WASM的时候,并且能提供更安全更快的API。
““**H3 是一个针对地球的空间划分和空间索引系统。由 Uber 在 2018年初正式开源。h3 将全球划分为不同分辨率的六边形的蜂窝小区,通过 Uber 公司 H3 Core Libary API 可以将经纬度坐标转移映射到六边形小区,从而实现了卫星通信路由区。
h3o 的由911个测试案例组成的基准套件已经被开发出来了,涵盖了整个公共API,并将h3o的性能与H3参考实现(通过h3ron-sys crate,预计没有开销)进行比较,h3o更快。
Gama 太阳帆的卫星于 2023 年 1 月 3 日由 SpaceX 猎鹰 9 号成功送入轨道。提供软件服务的应该是这家公司:Tweedegolf ,该公司也是 Rust 基金会银牌会员。他们的开源仓库里有一个 Rust 实现的 PTP (精确时间协议) 库,这个PTP一般用在卫星的时间源,比NTP更精确。但这个是 PoC 实现,不知道这次发射的飞船上有没有用。从另外的项目 嵌入式开发板 pcf85063a (一般用于计时闹钟)rust 驱动来看,这次上天的 Rust 程序很可能和精确计时相关。
法国民用航空公司空客(AirBus)开源了一份 全栈 Rust Web 开发架构指南 Rust on Nails。该指南也提供了一个应用案例 cloak。另外还发现了由空客和欧洲航天局合作开发的项目skytrace,该项目同样遵循 Rust on Nails 架构,旨在通过为卫星运营商提供数据共享和通信平台,提升太空态势感知能力。
还有民间 Rust 航空航天相关社区 AeroRust 社区也拿到了 Rust 基金会赞助:https://aerorust.org/blog/aerorust-3-years-birthday/
EVA ICS 是一个现代化的自动化、控制和监控平台,适用于各种需求,从家庭/办公室到工业设置。EVA ICS v4 是一款面向工业 4.0 自动化控制系统的新一代工业物联网平台,它是世界上最快的扩展自动化平台,可以在单个节点上处理数百万个对象和事件。工业级平台,实时、安全和可靠的事件复制,工业硬件通信协议即插即用。
目前有 Rust 开源实现 eva4,并且持续积极维护中。这个库是由波西米亚自动化/Altertech公司研发,该公司是一家拥有15年以上企业自动化和工业物联网经验的公司集团。它们的设备包括发电厂、工厂和城市基础设施。其中最大的设备拥有超过100万个传感器和可控设备,而且这个数字每天都在不断增长。目前 Rust 版本的 eva4 已经投入了生产,是之前 python版本的 100 倍。
EVA ICS 会保持开源(除了一些仅在企业套餐中提供的服务)。2023 年该公司计划基于 Rust SDK 集成它们自己的现场总线解决方案(应该是 sim 库),用于实时 PLC 应用程序(rplc,Rust 写 PLC 程序),以发展 Rust 在工业自动化领域的能力。
来源:推特 Daniel Bovensiepen Li @bovensiepen
““Today's Rust Meetup at Siemens introduced the application of Rust in train control networks. Things are moving
这一小节是我在 Rust 前沿报告中的第一次尝试,希望可以通过分析开源项目得到一些实践经验。所以先只选两个典型项目,一个是 Safe Rust 含量高,另一个是 Unsafe Rust 含量高。
qdrant 是 Rust 实现的向量数据库,目前已经拿到种子轮融资 750 万美元。虽然向量数据库是风口,但是能拿到种子轮也是不容易,因为竞争也很激烈。从这个角度来说,这个开源项目比同类实现应该是成功的。所以我们来分析这个项目。它们还推出了托管云(Azure云)解决方案,这是一个提供额外功能的DBaaS,解决了在生产环境中部署、维护和扩展矢量搜索数据库的需求。Qdrant 中大量使用 Safe Rust。
r4l,即 Rust for Linux,随着 Rust 落地 Linux 6.6 ,该项目目前看来也算是成功项目。该项目内含大量 Unsafe Rust 。我们可以从中学习 Unsafe Rust 安全抽象的一些实践。
我们从项目背景、架构设计和实现亮点这三个步骤来了解一个项目。
项目背景:
向量数据库。一个专门的生产级向量数据库需要解决向量存储内存占用、向量搜索准确率和检索性能的最佳平衡。
“这需要你去了解市面上真正生产级向量数据库正在解决什么问题,如何解决,技术局限在哪里。
架构设计:
Qdrant 首先是一个分布式数据库,其次它是一个向量数据库。
作为分布式数据库,Qdrant 在架构设计上属于中规中矩,就是常规的分布式数据库架构:利用 raft 解决分布式一致性,gRPC 在节点之间通信。
采用 Rust 生态常见的开源框架作为技术栈:
Rest API : Actix-web
gRPC: tonic
分布式一致性:raft
序列化与反序列化:serde(处理url编码和json)和 prost(处理 protobuf)
性能观测:trace
因为它本质是向量数据库,深入了解该项目的架构需要进一步去学习向量数据库的领域知识。下面是一些了解思路:
先阅读 Qdrant 官方文档。了解 Qdrant 代码架构背后抽象建模所面向的业务。基本可以了解到下面一些背景知识:
Qdrant支持对字符串 payload 进行全文搜索。
而 Qdrant 目前只使用 HNSW 作为向量索引。
Collection:就是一组命名的向量集合。但是在 Qdrant 里,向量用 Point 来表示。
Payload:Qdrant的一个重要特点之一是能够与向量一起存储附加信息。
Point:在 Qdrant 里,Point = (Vector + Payload)。你可以想象,它就是向量空间中的“点”。
相似性搜索:这就是向量数据库要提供的主要功能。在Qdrant术语中,这些方法被称为度量(metric)。度量的选择取决于向量的获取方式,特别是神经网络编码器训练的方法。Qdrant 支持 点积、余弦相似度和欧几里得距离。搜索是基于索引的。
索引(index):Qdrant的一个关键特点是向量和传统索引的有效结合。为了使向量搜索能够有效地与过滤器配合使用,仅仅拥有向量索引是不够的。简单来说,向量索引加快了向量搜索的速度,而payload 索引则加快了过滤器的速度。
存储:向量数据库的存储结构和传统数据库不同。Collection 中的 Points 被存储到更小的 Segment 片段中,每个 Segment 有自己独立的索引。Segment 还被设计为 读写分离结构。并且支持内存存储和Memmap存储(为存储在磁盘上的存储文件中的内容创建内存映射)。
快照(Snapshots):功能可用于存档数据或轻松复制现有部署。
在了解完。qdrant 的领域设计之后,就可以选择性地阅读它的源码来了解架构了。
存储:看 存储系统是如何架构的。围绕 Collection 和 Segment 。只关注内存存储。
索引:关注向量索引相关的代码架构,看如何建立混合索引。
这样可以把握 Qdrant 的整理架构,然后再逐渐从生产级优化方向入手去深入了解,比如分布式、向量内存占用优化、聚类算法之类的。
实现亮点:
Qdrant 选择 HNSW 算法作为唯一的向量索引,那么它的 Rust 实现就是一种亮点,值得深入学习。
(Hierarchical Navigable Small World Graph)是一种基于图的索引算法。它根据一定的规则为图像构建了一个多层导航结构。在这个结构中,上层更稀疏,节点之间的距离更远。下层更密集,节点之间的距离更近。搜索从最上层开始,在该层中找到最接近目标的节点,然后进入下一层开始另一次搜索。经过多次迭代,它可以快速接近目标位置。为了提高性能,HNSW限制了图中每个层的节点的最大度数为 m
。此外,在构建索引时,你可以使用 ef_construct
来指定搜索范围,在搜索目标时,您可以使用 ef
来指定搜索范围。
项目背景:
Rust for Linux 主要是为了给 Linux 中添加 Rust 支持。但并不是说简单地给 Linux 发行版里安装一套 Rust 工具链就完事了。该项目的主要目标是,给 Linux 内核开发者提供一个安全的 Rust kernel SDK。
这些 Linux 内核开发者使用这一套 Rust kernel SDK 就可以放心地安全地进行 Linux 内核驱动开发,而避免直接使用 Unsafe Rust 。这套 SDK 就是 kernel
crate。
这就意味着, Rust for Linux 中提供的这个 kernel
crate ,必须是对 Linux 内核 API 进行安全的封装,并且设计出具有人体工效的 API ,才能体现出 Rust 语言的真正优势。
所以,我们学习 Rust for Linux 的代码,主要是为了学习如何优雅安全地用 Rust 来包装 C-ABI 接口。目前,Rust 通过 FFI 和 C-ABI 打交道,是 Rust 系统级开发应用领域无法逾越的障碍。因为这个世界目前就是 C “统治”的,C 经过这 40 多年的沉淀已经成为了“硬件接口层”了。
架构设计:
在 linux/rust
根目录下,主要包含着四大模块:
alloc
,这里主要是由 rust for linux 从上游的 Rust 项目 fork 出来的,因为直接使用当前 Rust 项目中的 alloc 提供的接口无法满足 liunx 的需求。这也是 Rust for Linux 反向推进 Rust 演进的一个案例。它促进了 Rust alloc crate 接口的进化。
bindings
,这里主要是对 Linux 内核 C API 的绑定层。一般来说,都会以 -sys
来命名,但是这里直接用了 bindings 这个词,也是可以的。
kernel
,这是 Rust 对 Linux 内核 API 安全抽象和优雅设计的主要模块。
macros
,提供一些安全的宏,可以尽可能地隐藏一些 unsafe 调用,避免直接把 unsafe 面向内核开发者。
其中的看点在 kernel
内,该模块结合了 Linux 的标准安全要求,有一些独特设计。这些都可以在每次给上游 Linux 提交的 PR 邮件说明中看到改进细节。
实现亮点:
我们用 Rust for Linux kernel
模块中一个独立的 clk
时钟功能的部分代码来展示一下 Unsafe Rust 如何安全抽象。
安全抽象两个原则:
整体上维护安全不变量
保证指针内存数据的有效性
“来源:https://github.com/Rust-for-Linux/linux/blob/rust/rust/kernel/clk.rs
/// Represents `struct clk *`.
///
/// # Invariants
///
/// The pointer is valid.
pub struct Clk(*mut bindings::clk);
impl Clk {
/// Creates new clock structure from a raw pointer.
///
/// # Safety
///
/// The pointer must be valid.
pub unsafe fn new(clk: *mut bindings::clk) -> Self {
Self(clk)
}
/// Returns value of the rate field of `struct clk`.
pub fn get_rate(&self) -> usize {
// SAFETY: The pointer is valid by the type invariant.
unsafe { bindings::clk_get_rate(self.0) as usize }
}
/// Prepares and enables the underlying hardware clock.
///
/// This function should not be called in atomic context.
pub fn prepare_enable(self) -> Result {
// SAFETY: The pointer is valid by the type invariant.
to_result(unsafe { bindings::clk_prepare_enable(self.0) })?;
Ok(EnabledClk(self))
}
}
代码中,结构体 Clk
包装了来自 Linux 内核 Clock API 的 C 指针 *mut bindings::clk
。
一般来说,对于这种情况,我们应该为其建立安全不变量。
这里如何定义安全不变量?实际上并没有。如果要构建安全不变量,则 new
方法应该检查指针是否为空。
pub fn new(cptr: *mut bindings::cptr) -> Self {
if cptr.is_null() {
panic!("CPtr should not be null!")
}
Self(cptr)
}
但是这里的情况比较特殊,在 Linux 内核代码中,不允许 Panic 。
所以现在的new
是 unsafe 的,让调用该方法的开发者来保证提供的指针必须是有效指针。所以这里只是提供了有效性不变量,但如果想让它安全,还必须让调用者保证这个有效性不变量。
对于get_rate
和prepare_enable
方法而言,它们的安全性不变量也是建立在 new
方法传入的指针是否有效的基础上。
所以,我们能否说这段代码是不健全的呢?当然不能。因为它本来就没有提供安全性不变量。讨论代码是否健全的前提是在提供安全性不变量基础上的。
当今世界正在经历一场 从 Cpp 到 Rust 的转换。首当其冲的就是我们之前说过的这些商业巨头,为了可持续发展。安全将是必选项,而又无法指望每个程序员们都能有安全意识和高超的编码技能,况且,只要是人,就会有犯错的时候。所以选择 Rust 语言是时代的趋势。
但是也不可能把所有的遗留 C/Cpp 项目都用 Rust 重新实现,而让 Rust 与 C/Cpp “和平共处” 才是当下必须要掌握的安全实践。
这方面最好的实践案例是 Google 。因为它们的代码都是开源的,而且已经取得了内存安全成果,比如 Android 。同时也开源了一些 Rust 和 C/Cpp 互操安全工具,比如 crubit, 这是 Google 内部多年(至少四年)沉淀下来的解决方案。
Rust 与 C/Cpp 交互,无外乎可以分为以下两类情况:
Rust 直接与 Cpp 交互。
Rust 通过 C-ABI 与 Cpp 交互。
Rust 直接与 Cpp 交互是不太可能的,否则 Google 也不会再一门专门与 C++ 交互的新语言 Carbon 。
所以,目前生产环境 Rust 和 Cpp 直接交互主要还是通过第二种方式:通过 C-ABI 。开源社区的 cxx
可以让 Rust 和 Cpp 安全交互,在底层实际也是使用了 C-ABI,只不过对开发者隐藏了而已。
![[Screenshot 2023-08-04 at 12.14.09.png]]
cxx
可以帮你处理 C-ABI FFI 常见的三类调用:
共享数据结构。
不透明类型。这些类型不能通过值传递跨越 FFI,只能通过间接方式传递,比如引用、trait对象之类。
回调函数。
当你不使用 cxx
的时候,你需要手工安全处理这三类调用。
什么时候使用 cxx ?
cxx
在 Android 里面也被大量使用,证明它是非常成熟的。比如蓝牙模块。使用 cxx 意味着要自动生成 C-ABI 接口的 Rust 绑定代码,以及 Rust 和 Cpp 的安全桥接代码。
这里面存在两种情况:
遗留的 Cpp 模块会逐渐像新的 Rust 模块迁移,而旧的 Cpp 模块将不再更新使用。这种情况无疑直接使用 cxx
是最方便的。因为你不用担心更新遗留 cpp 代码有什么不兼容问题。比如,使用 cxx 允许蓝牙团队更容易地为遗留协议(如HIDL)提供服务,直到通过使用现有的C++支持逐步迁移他们的服务来逐步淘汰这些协议。
遗留的 Cpp 模块还会继续更新,只是当前部分模块迁移到 Rust 。这种情况无疑是使用手工为 Cpp 库实现一层 C 接口,再用 Rust 绑定(可以使用bindgen自动,也可以手动实现)。在这个基础上,遵循 Unsafe Rust 安全抽象原则进行实现就可以了。
FFI Safety
FFI Safety 是处理 Rust 和 C-ABI 安全交互的一个重要问题。依然涉及以下方面:
1. 共享数据结构
有时候需要将 Cpp 分配内存里的数组在 Rust 中也需要使用。这就涉及 Rust 内存再分配和数据拷贝。这里面一定要把内存布局、字节对齐、长度等基本数据结构映射正确。
use std::mem;
use std::slice;
extern "C" {
// 假设这是一个 C++ 函数,返回一个指向 C++ 分配的内存的指针
fn get_data_from_cpp() -> *const u8;
// 假设这是一个 C++ 函数,返回数据的长度
fn get_data_length() -> usize;
}
fn main() {
unsafe {
let data_ptr = get_data_from_cpp();
let data_len = get_data_length();
// 创建一个 Rust 切片,指向 C++ 分配的内存
let data_slice = slice::from_raw_parts(data_ptr, data_len);
// 在 Rust 中分配内存,并拷贝数据
let data_vec = data_slice.to_vec();
// 现在,data_vec 是一个 Rust Vec,可以在 Rust 中使用
println!("{:?}", data_vec);
}
}
有时候需要将 Cpp 分配内存里的数组转换为 Rust 中的切片,这样可以避免 Rust 内存再分配和数据拷贝。但是直接转换为 Rust 的切片需要注意内存布局一定是字节对齐、内存数据在 Rust 切片整个运行生命周期内是有效的。
use std::slice;
extern "C" {
// 假设这是一个 C++ 函数,返回一个指向 C++ 分配的内存的指针
fn get_data_from_cpp() -> *const u8;
// 假设这是一个 C++ 函数,返回数据的长度
fn get_data_length() -> usize;
}
fn main() {
unsafe {
let data_ptr = get_data_from_cpp();
let data_len = get_data_length();
// 创建一个 Rust 切片,指向 C++ 分配的内存
let data_slice = slice::from_raw_parts(data_ptr, data_len);
// 现在,data_slice 是一个 Rust 切片,可以在 Rust 中使用
println!("{:?}", data_slice);
}
}
2. 不透明类型
这些类型不能通过值传递跨越 FFI,只能通过间接方式传递,比如引用、trait对象之类。rust 中的引用包含了一些指针元数据,如果将其直接传给 C 接口,会丢失很多信息。然而,我们在实现一些动态库插件系统的时候也必须要传递这种类型,比如 trait 对象。因为 Rust 语言 ABI 未稳定,所以需要依赖一些第三方库,比如 abi_stable/async_ffi
等,相比手工处理更加安全。
use abi_stable::RustBox;
trait Animal {
fn make_sound(&self);
}
struct Dog;
impl Animal for Dog {
fn make_sound(&self) {
println!("Woof!");
}
}
// C++ 接口
extern "C" {
fn callback(animal: RustBox);
}
fn main() {
let dog = Dog;
// 使用 RustBox 包装 trait 对象
let boxed_dog = RustBox::new(dog);
// 安全地通过 FFI 调用传递 boxed_dog
unsafe { callback(boxed_dog) };
}
“RustBox 在内部持有一个指向trait对象的原始指针。同时,它会处理这个原始指针的相关元数据(比如长度、偏移、vtable等),以使指针本身可以安全地通过 FFI 边界。
3. 函数
在 Rust 和 C 两边相互调用函数,或传递回调函数,需要做到下面几点。
谁分配内存,谁来释放
函数参数类型必须兼容 C-ABI
函数内需要考虑安全边界,比如指针判空、是否越界、是否存在数据竞争等等情况
extern crate libc;
#[link(name = "get_attestation")]
extern "C" {
fn get_attestation(data: [libc::c_char; 64], report: [libc::c_char; 4096]) -> libc::c_int;
}
fn main() {
let data: [i8; 64] = [0; 64];
let mut report: [i8; 4096] = [0; 4096];
let ret = unsafe {
get_attestation(data, report)
};
// drop(data);
// drop(report);
//println!("report is {:?}", report);
println!("ret is {:?}", ret);
}
// warning: `extern` block uses type `[i8; 4096]`, which is not FFI-safe
// --> src/main.rs:5:58
// |
// 5 | fn get_attestation(data: [libc::c_char; 64], report: [libc::c_char; 4096]) -> libc::c_int;
// | ^^^^^^^^^^^^^^^^^^^^ not FFI-safe
// |
// = help: consider passing a pointer to the array
// = note: passing raw arrays by value is not FFI-safe
作为 Rust 代码审查者,需要有一份 Checklist 来指导自己的日常审查工作:
是否遵循 Rust 通用编码规范 √
代码组织结构是否合理 √
代码抽象架构是否合理,是否具有扩展性 √
代码封装性是否合理 √
错误处理是否完备统一合理 √
是否遵循 Unsafe Rust 安全抽象实践 √
代码单元测试是否达到指定覆盖率 √
以及特别指定必要测试:性能测试 和 模糊测试
文档注释和普通注释是否完整和合理 √
代码优化 :
是否存在肉眼可见的性能优化问题 √
编译文件大小是否需要优化 √
代码中是否包含重复代码 √
欢迎大家补充。
“Mojo 语言官方最近发布了一篇文章,探讨 Rust 和 Mojo 这两种编程语言在未来 AI 领域的应用可能性。原文:https://mojodojo.dev/blog/2023-07-17-rust-or-mojo-ai.html
当前机器学习模型在投入到生产遇到的一些迫切的问题是,业内现在 C/C++ 和 Python 的流行组合存在一些不满意的地方。
理想情况下,我们希望可以有一种语言,既能让系统程序员将硬件性能发挥到物理极限,又能作为一种安全的高级语言,使代码投入生产变得简单、可靠且高效。Rust 就很好地适应了这个空间,尽管学习曲线陡峭,但它已经开始在业界被注意到作为一种可能的解决方案。
将使用计算机视觉机器学习模型的生产代码从C/C++/Python转换为Rust是一种美妙的体验,表面上看,Rust作为一种高级、安全和表达力强的语言,在性能开销非常低的同时表现出色。
但是,Rust生态系统仍然年轻,因此我们仍然依赖于像 opencv 这样的大型C++项目,而opencv本身又依赖于像ffmpeg这样的大型C++项目,用于图像和视频编码和解码。与这些库进行链接的经验可能非常痛苦,特别是在静态链接时,而从SIMD寄存器或其他专用硬件中挤取性能则需要更多的复杂性。当你最终以数百兆字节的依赖项包装C/C++到不安全的Rust时,这种感觉开始变得多余。
Rust 在这个方面也做过努力,从2019年就开始了,比如 opencv-rust 和 tract-onnx 。但是这些库贡献者非常少,而且都是独立开发者。
由于绝大多数人工智能研究人员都是使用Python,而且对学习 Rust 不感兴趣,因此很不可能在机器学习领域得到广泛应用。对于研究人员来说,它永远不会像 opencv-python
, numpy
, pytorch
等组合那样方便易用。
所以,文章得出结论,作者非常喜欢使用 Rust 进行计算机视觉工作,因为它是一种有趣的语言,但添加复杂性不会帮助生态系统,它迫切需要简化。作者认为,Mojo 由于专注于简化这个过程,同时允许 AI 研究人员从 Python 与他们的代码交互,因此他相信 Mojo 将是行业的未来发展方向。
Mojo 通过兼容 Python 语法和生态库想完全复用 Python 的机器学习生态。Mojo 在语言特性上也向 Rust /Zig/ Julia 语言学习。底层基于 MLIR ,Mojo中的所有内容都转化为MLIR,用于生成针对硬件特定优化的代码。
“_MLIR_(多级中间表示)是语言(如C)或库(如TensorFlow)与编译器后端(如LLVM)之间的中间表示(IR) 系统。主要用于机器学习领域。它是由Chris Lattner (现在也是 Mojo 语言之父)及其在Google的团队构建的,作为LLVM的继任者,因为它允许ML和异类硬件类型所需的模块化。此后,它被开源并广泛采用,并被纳入LLVM项目中。它仍然使用传统的LLVM基础架构进行CPU代码生成和优化。
Modular 团队开发了一个 MLIR 方言 pop
,它并不是为了普通程序员使用,随着时间的推移,有用的东西将会被编译器工程师封装成一个漂亮的API,供系统工程师和 Python 程序员在更高的层次上使用。它主要是可以让编译器工程师为不同的硬件编写优化,随着人工智能加速变得更加高级,Mojo开发者将能够充分利用这一优势。除此之外,Mojo 还支持 SIMD 等优化手段。这里就不细说。
从这篇文章描述的机器学习生态痛点,以及 Mojo 语言提供的解决方案来看,Mojo 确实在机器学习领域有巨大的潜力。但目前 Mojo 终究还是一门新生的婴儿语言,能否达到它理想中的状态,还需要很长时间。
而 Rust 语言自身已经到达一个已经成熟的状态,而且现在一些人工智能行业的公司也有在投入 Rust ,并且也准备用 Rust 来填补缺失的生态,最主要的是因为他们喜欢 Rust 。
所以,Mojo 虽然极具潜力,但是 Rust 语言还是有很多时间来和 Mojo 在机器学习领域竞争一下。
Rust 语言作为新时代的系统级通用语言,应用面非常广泛,是你工作学习必备的一门语言。至于 Mojo 语言,可以根据你自身的需求选择性学习,毕竟它现在还没有成熟,如果你是 AI 核心从业者,那么 Mojo 对你而言就非常值得学习了。
关于 Rust 和 Mojo 的比较,可以参考我另一篇文章:大模型时代的系统语言:Rust vs Mojo
ChatGPT 或 Claude.ai 都很不错。
之前 UB 代码被 GPT 修正:
修正后的代码:
extern crate libc;
#[link(name = "get_attestation")]
extern "C" {
fn get_attestation(data: *const libc::c_char, report: *mut libc::c_char) -> libc::c_int;
}
fn main() {
let data: [i8; 64] = [0; 64];
let mut report: [i8; 4096] = [0; 4096];
let ret = unsafe {
get_attestation(data.as_ptr(), report.as_mut_ptr())
};
// drop(data);
// drop(report);
//println!("report is {:?}", report);
println!("ret is {:?}", ret);
}
也借助 Copilot 这类 AI 助手帮你自动生成代码,效率加倍。
使用 Prompt 提升 AI 助手效率:RustChat。
2021.6 三万言|2021 年 Rust 行业调研报告
2022.01
年终盘点 Rust 生态版图 | 星辰大海(上篇)
年终盘点 Rust 生态版图 | 星辰大海(下篇)
2023.01 Rust 2022 生态版图年度报告