fixed_vec
一个减少数组冗余边界检查的库rust的Vec
在使用索引的时候总会触发边界检查,在某些时候降低了程序的性能。通常解决方法是尽可能使用迭代器来处理数组。
本文通过Ghosts of Departed Proofs (https://kataskeue.com/gdp.pdf) 这篇论文中讨论的技术来减少Rust中冗余边界检查。
具体内容: https://github.com/Torrencem/fixed_vec/blob/master/post.md
在文末有提到了性能差距,如果只想看看效果如何的,可以直接跳到文末
代码示例
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...
Github仓库: https://github.com/Torrencem/fixed_vec
主要是移除了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
WebAssembly
线程和引用类型!这是一个很大的进步,意味着Rust的借用检查器可以在web里大展拳脚了。
https://hacks.mozilla.org/2020/07/firefox-79/
视频内容大概有actix、rocket等一系列web线管的实战视频,挺有意思的。
油管博主主页:Genus-v Programming: https://www.youtube.com/channel/UCSkHbGjrjJmuAbDPhIQ5T0A
B站有人搬运:Rust web框架教程: https://www.bilibili.com/video/BV1sD4y1S7QL?p=1
Amethyst
更新了一个地图编辑器在github该仓库页面有地图编辑器的使用示例
Amethyst
是rust编写的游戏引擎,最近一年的更新动静较小,主要是集中力量完成了对wasm的支持。在一月份对wasm支持之后开始有了点动静。
Github仓库: https://github.com/amethyst/voxel-mapper
Richter
雷神之锤游戏的Rust实现图形后端用的是wgpu
目前正在积极开发中
主页: http://c-obrien.org/richter/
Github仓库: https://github.com/cormac-obrien/richter
Deno
最近更新了typescript使用的编译器Deno
现在使用SWC(一个Rust写的TS/JS编译器),类型剥离的性能从之前的大约1s变成了现在的大约70ms
https://github.com/denoland/deno/issues/5432#issuecomment-665591700
文章分为两部分,第二部分还没有发出来
https://ebbflow.io/blog/vending-linux-1
hawk 是Knoldus公司的一个 Rust 应用案例,它是一个物联网安全门禁系统。基于Rust、S3、Rekognition、Lambda等服务实现,这些都是亚马逊提供的云服务。
整个项目的逻辑是这样的:
门禁卡那有个树莓派,给雇员拍一张照片,然后雇员的RFID 卡扫描以后,会触发树莓派里的照片上传到S3,然后通过lambda根据雇员id,去另一个S3里调用员工的照片,然后用 第三方图片识别服务,把树莓派拍摄的照片和S3里存储的照片进行相似性比对,返回一个分数,返回到树莓派上面,这个值大于一定值就开门。
项目的源码不是很多,可以学习下。
https://www.knoldus.com/work/case-studies/hawk-rust-iot
https://github.com/knoldus/hawk
活动地址: https://rusty-days.org/agenda/
部分录播地址: https://www.youtube.com/playlist?list=PLf3u8NhoEikhTC5radGrmmqdkOK-xMDoZ
the rust borrow checker 大概在2:24左右开始
这两天刚举办的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++ 已经证明了。
视频地址: https://www.youtube.com/watch?v=XFhrb-qLX_8&list=PLf3u8NhoEikhTC5radGrmmqdkOK-xMDoZ&index=2&t=0s
注意这个视频是 33 分钟以后才开始的
分享者:Nell Shamrell-Harrington ,Mozilla员工
该Topic议程分为两部分: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
(看完后发现,好像也没有很深入)
视频地址: https://www.youtube.com/watch?v=XFhrb-qLX_8&list=PLf3u8NhoEikhTC5radGrmmqdkOK-xMDoZ&index=2&t=0s
注意这个Topic 在 2小时以后
从代码看上去似乎是通过函数空指针调用了函数
代码Playground
fn foo() {
println!("This is really weird...");
}
fn caller() where F: FnMut() {
let closure_ptr = 0 as *mut F;
let closure = unsafe { &mut *closure_ptr };
closure();
}
fn create(_: F) where F: FnMut() {
let func_ptr = caller:: as fn();
func_ptr();
}
fn main() {
create(foo);
create(|| println!("Okay..."));
let val = 42;
create(|| println!("This will seg fault: {}", val));
}
作者本人对这部分代码能够正常运行感到疑惑,特别是为什么foo函数能够被caller
函数里强制转化成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::
(using the name from the error message), the expression caller::
constructs a function pointer to caller::
. Invoking this function pointer is the same as calling caller::
directly, and this is also the only function pointer in the whole program. Finally, in caller::
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的建议查看原文
https://stackoverflow.com/questions/63164973/wat-code-rust-allows-calling-functions-via-null-pointers
From 日报小组 Downtime Jancd
社区学习交流平台订阅:
Rust.cc 论坛: 支持 rss
微信公众号:Rust语言中文社区