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吗?这里做一些关键点梳理:
视频地址: 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 生成机器码。
深入借用检查:
借用检查器的工作:
(看完后发现,好像也没有很深入)
视频地址: 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<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!
https://stackoverflow.com/questions/63164973/wat-code-rust-allows-calling-functions-via-null-pointers
From 日报小组 Downtime Jancd