【Rust日报】2020-07-30 fixed_vec减少Rust数组冗余边界检查

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

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里大展拳脚了。

https://hacks.mozilla.org/2020/07/firefox-79/

在油管发现一个专门更新Rust实战相关视频的博主

视频内容大概有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

为Linux系统打包Rust项目

文章分为两部分,第二部分还没有发出来

https://ebbflow.io/blog/vending-linux-1

hawk:Rust 在物联网领域的一个学习案例

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

rusty days活动

活动地址: https://rusty-days.org/agenda/

部分录播地址: https://www.youtube.com/playlist?list=PLf3u8NhoEikhTC5radGrmmqdkOK-xMDoZ

the rust borrow checker 大概在2:24左右开始

关于2021-edition:

这两天刚举办的rusty days线上 Rust 大会,steve 讲了一个Topic,需要有2021-edition吗?这里做一些关键点梳理:

  1. 里面提到 Edition 的作用范围:允许增加新的关键字,改进语法,但不允许去对语言一致性、标准库等进行根本性破坏。

  2. 回顾编译器的编译过程:a. rustc 是多道编译器,从源码到 AST -> HIR(大部分检查、类型检查、方法查找) -> MIR(借用检查) -> LLVM IR b. rustc 是 基于查询 (query-based) 的编译器

  3. 对于 编译器来说,所有 Edition 的代码,在 MIR 层面都不允许存在差异,即, MIR 是多个Edition的通用语言。对于 人类开发者来说,Edition 之间会有差异,但不会太多。生态系统也不会搞的像主版本变化那样分裂。

  4. Rust 的发布周期是比较固定的,Nightly是每晚,beta和stable是每六周发布一版。但是 Edition现在还没有确定。那什么时候用 Edition呢? 回顾过去的Rust 2018,可以说是即成功又不成功。成功是说,Rust 团队达成了既定目标,并且完成了一个艰巨的任务。不成功的地方在于,发布的东西其实并不是计划的全部,并且团队成员长期工作带来了巨大的疲劳和怠倦。Rust 团队想做的太多,但是他们低估了投入成本。

  5. 不过,steve表示, 我们应该有一个 Rust 2021 Edition。但它应该比Rust 2018更小的版本,小版本优点会大于缺点。并且在未来保持一个「发行列车」,即便三年内没有什么大的特性,也会坚持发布一个Edition。对于不使用 Rust 的人,不应该来频繁地关注Rust Edtion的发布信息,他们只需要知道 Rust 已经很稳定就够了!对于使用Rust的人来说,每三年的 Edition,其实就是一个 「总结」。

  6. 2021 edition 应该有什么特性呢?steve表示其实他并不在意,不必要非得刻意规定什么特性来证明Edition的合理性,哪怕有一个特性错过了发布,那么三年后发布就可以了。但是,Rust 官方会在 10月份以后发布一个 RFC 的,目前主要是 Niko 和 Steve 在做这个,当然,Niko 还是主力担当。

  7. 为什么是三年呢?一年一次有点过,五年一次太长,三年节奏刚刚好,这一点 c++ 已经证明了。

视频地址: https://www.youtube.com/watch?v=XFhrb-qLX_8&list=PLf3u8NhoEikhTC5radGrmmqdkOK-xMDoZ&index=2&t=0s
注意这个视频是 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 生成机器码。

深入借用检查:

借用检查器的工作:

  1. 跟踪变量的初始化和move

  2. 生命周期推导(Lifetime inference) a. 变量的生命周期 b. 引用的生命周期。如果引用一个值,则该引用的生命周期不能超过该值的作用域。

  3. 还有很多其他功能,继续参阅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小时以后

Stackoverflow里有人探索Rust中的函数指针魔法,写出了一个奇怪的东西

从代码看上去似乎是通过函数空指针调用了函数

代码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:: as fn() 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语言中文社区

你可能感兴趣的:(编译器,java,编程语言,go,人工智能)