fixed_vec
一个减少数组冗余边界检查的库
rust的Vec
在使用索引的时候总会触发边界检查,在某些时候降低了程序的性能。通常解决方法是尽可能使用迭代器来处理数组。
本文通过Ghosts of Departed Proofs这篇论文中讨论的技术来减少Rust中冗余边界检查。
在文末有提到了性能差距,如果只想看看效果如何的,可以直接跳到文末
代码示例
use fixed_vec::{name, FixedVec};
let v = vec![0u32; 10];
let v = name!(v);
let mut v = FixedVec::fix(v);
// Perform the two index checks here:
let index_a = v.check_index(...).unwrap();
let index_b = v.check_index(...).unwrap();
for _ in 0..100 {
// These do *not* perform bounds checks!
// At compile time, v and index_a must match
*v.get_mut(index_a) += 5;
*v.get_mut(index_b) += 10;
}
let v = v.unfix();
// continue using v...
Rust 标准库准备从 libbacktrace 迁移到 gimli
主要是移除了libgcc.so 的依赖,换成了纯 Rust 的gimli
https://github.com/rust-lang/rust/pull/74682
https://github.com/gimli-rs/gimli
消息来自 Google 工程师Benjamin的推:https://twitter.com/Brittain_Ben/status/1288193388588740615
Firefox 79现在支持WebAssembly
线程和引用类型!
这是一个很大的进步,意味着Rust的借用检查器可以在web里大展拳脚了。
在油管发现一个专门更新Rust实战相关视频的博主
视频内容大概有actix、rocket等一系列web线管的实战视频,挺有意思的。
油管博主主页:Genus-v Programming
B站有人搬运:Rust web框架教程
Amethyst
更新了一个地图编辑器
在github该仓库页面有地图编辑器的使用示例
Amethyst
是rust编写的游戏引擎,最近一年的更新动静较小,主要是集中力量完成了对wasm的支持。在一月份对wasm支持之后开始有了点动静。
Richter
雷神之锤游戏的Rust实现
图形后端用的是wgpu
目前正在积极开发中
Deno
最近更新了typescript使用的编译器
Deno
现在使用SWC(一个Rust写的TS/JS编译器),类型剥离的性能从之前的大约1s变成了现在的大约70ms
为Linux系统打包Rust项目
文章分为两部分,第二部分还没有发出来
hawk: Rust 在物联网领域的一个学习案例
hawk 是Knoldus公司的一个 Rust 应用案例,它是一个物联网安全门禁系统。基于Rust、S3、Rekognition、Lambda等服务实现,这些都是亚马逊提供的云服务。
整个项目的逻辑是这样的:
门禁卡那有个树莓派,给雇员拍一张照片,然后雇员的RFID 卡扫描以后,会触发树莓派里的照片上传到S3,然后通过lambda根据雇员id,去另一个S3里调用员工的照片,然后用 第三方图片识别服务,把树莓派拍摄的照片和S3里存储的照片进行相似性比对,返回一个分数,返回到树莓派上面,这个值大于一定值就开门。
项目的源码不是很多,可以学习下。
rusty days活动
部分录播地址the rust borrow checker 大概在2:24左右开始
关于2021-edition:
这两天刚举办的rusty days线上 Rust 大会,steve 讲了一个Topic,需要有2021-edition吗? 这里做一些关键点梳理:
-
里面提到 Edition 的作用范围: 允许增加新的关键字,改进语法,但不允许去对语言一致性、标准库等进行根本性破坏。
-
回顾编译器的编译过程: a. rustc 是多道编译器,从源码到 AST -> HIR(大部分检查、类型检查、方法查找) -> MIR(借用检查) -> LLVM IR b. rustc 是 基于查询 (query-based) 的编译器
-
对于 编译器来说,所有 Edition 的代码,在 MIR 层面都不允许存在差异,即, MIR 是多个Edition的通用语言。 对于 人类开发者来说,Edition 之间会有差异,但不会太多。生态系统也不会搞的像主版本变化那样分裂。
-
Rust 的发布周期是比较固定的,Nightly是每晚,beta和stable是每六周发布一版。但是 Edition现在还没有确定。那什么时候用 Edition呢? 回顾过去的Rust 2018,可以说是即成功又不成功。 成功是说,Rust 团队达成了既定目标,并且完成了一个艰巨的任务。 不成功的地方在于,发布的东西其实并不是计划的全部,并且团队成员长期工作带来了巨大的疲劳和怠倦。 Rust 团队想做的太多,但是他们低估了投入成本。
-
不过,steve表示, 我们应该有一个 Rust 2021 Edition。但它应该比Rust 2018更小的版本,小版本优点会大于缺点。并且在未来保持一个「发行列车」,即便三年内没有什么大的特性,也会坚持发布一个Edition。 对于不使用 Rust 的人,不应该来频繁地关注Rust Edtion的发布信息,他们只需要知道 Rust 已经很稳定就够了! 对于使用Rust的人来说,每三年的 Edition,其实就是一个 「总结」。
-
2021 edition 应该有什么特性呢? steve表示其实他并不在意,不必要非得刻意规定什么特性来证明Edition的合理性,哪怕有一个特性错过了发布,那么三年后发布就可以了。 但是,Rust 官方会在 10月份以后发布一个 RFC 的,目前主要是 Niko 和 Steve 在做这个,当然,Niko 还是主力担当。
-
为什么是三年呢? 一年一次有点过,五年一次太长,三年节奏刚刚好,这一点 c++ 已经证明了。
视频地址 注意这个视频是 33 分钟以后才开始的
首届 Rusty Day 线上大会散记: 深入借用检查器
分享者:Nell Shamrell-Harrington ,Mozilla员工
该Topic议程分为两部分: Rust编译器概述 和 深入借用检查器
Rust 编译器概述:
介绍了编译阶段:词法、解析、语义分析、优化、代码生成
Token -> AST -> HIR -> MIR -> LLVM IR
在 AST 阶段主要做的工作:宏展开、去糖、处理各种模块导入 HIR的数据结构: Crate(CrateNum) < Definition(DeId) < Node (HirId) > > MIR 的数据结构: Control Flow Graph < bb0(statement -> statement -> terminator ) -> bb1(statement -> terminator ) -> bb2 ((statement > terminator )... >
详细内容可以参阅: https://rustc-dev-guide.rust-lang.org/
优化主要在 MIR 和 LLVM IR 阶段完成,最终由 LLVM IR 通过 LLVM 生成机器码。
深入借用检查:
借用检查器的工作:
- 跟踪变量的初始化和move
- 生命周期推导(Lifetime inference) a. 变量的生命周期 b. 引用的生命周期。如果引用一个值,则该引用的生命周期不能超过该值的作用域。
- 还有很多其他功能,继续参阅rustc dev guide。 (比如 检查不可变和可变借用等)。 https://rustc-dev-guide.rust-lang.org/borrow_check.html
(看完后发现,好像也没有很深入)
视频地址 注意这个Topic 在 2小时以后
Stackoverflow里有人探索Rust中的函数指针魔法,写出了一个奇怪的东西
从代码看上去似乎是通过函数空指针调用了函数
fn foo() {
println!("This is really weird...");
}
fn caller<F>() where F: FnMut() {
let closure_ptr = 0 as *mut F;
let closure = unsafe { &mut *closure_ptr };
closure();
}
fn create<F>(_: F) where F: FnMut() {
let func_ptr = caller::<F> as fn();
func_ptr();
}
fn main() {
create(foo);
create(|| println!("Okay..."));
let val = 42;
create(|| println!("This will seg fault: {}", val));
}
作者本人对这部分代码能够正常运行感到疑惑,特别是为什么foo函数能够被caller<F>()
函数里强制转化成nullptr
调用。
已经有大神对这个问题做出了解释,太长了我直接贴地址。中文社区的大佬如果对这个问题感兴趣,可以帮忙在这里回复一下。
可能有小伙伴访问StackOverflow比较缓慢,这里我复制高赞回复的原文:
This program never actually constructs a function pointer to anything but caller
- it always invokes foo
and those two closures directly.
Every Rust function, whether it's a closure or a fn
item, has a unique, anonymous type. This type implements the Fn
/FnMut
/FnOnce
traits, as appropriate. The anonymous type of a fn
item is zero-sized, just like the type of a closure with no captures.
Thus, the expression create(foo)
instantiates create
's parameter F
with foo
's type- this is not the function pointer type fn()
, but an anonymous, zero-sized type just for foo
. In error messages, rustc calls this type fn() {foo}
, as you can see this error message.
Inside create::<fn() {foo}>
(using the name from the error message), the expression caller::<F> as fn()
constructs a function pointer to caller::<fn() {foo}>
. Invoking this function pointer is the same as calling caller::<F>()
directly, and this is also the only function pointer in the whole program.
Finally, in caller::<fn() {foo}>
the expression closure()
desugars to FnMut::call_mut(closure)
. Because closure
has type &mut F
where F
is just the zero-sized type fn() {foo}
, the 0
value of closure
itself is simply never used(注释1), and the program calls foo
directly.
The same logic applies to the closure || println!("Okay...")
, which like foo
has an anonymous zero-sized type, this time called something like closure@src/main.rs:2:14: 2:36.
The second closure is not so lucky- its type is not zero-sized, because it must contain a reference to the variable val
. This time, FnMut::call_mut(closure)
actually needs to dereference closure
to do its job. So it crashes(注释2)
注释1 Constructing a null reference like this is technically undefined behavior, so the compiler makes no promises about this program's overall behavior. However, replacing 0 with some other "address" with the alignment of F avoids that problem for zero-sized types like fn() {foo}, and gives the same behavior!) 注释2 Again, constructing a null (or dangling) reference is the operation that actually takes the blame here- after that, anything goes. A segfault is just one possibility- a future version of rustc, or the same version when run on a slightly different program, might do something else entirely!
后续还有不少回复,能直接访问StackOverflow的建议查看原文
From 日报小组 Downtime Jancd
社区学习交流平台订阅:
评论区
写评论赞!内容好丰富