https://zhuanlan.zhihu.com/p/90612241

今天(2019-11-07)Rust终于发布了期待已久的v1.39版本,增加了重量级的async/await关键字支持。Rust作为一个2015年才发布正式版的新星,使用人数寥寥,却能在StackOverflow发起的“最喜爱的编程语言”年度投票中连续四年蝉联第一。Rust凭什么能够击败Python等众多语言连续四年制霸?这一切的背后有着什么样的秘密?是人性的扭曲还是道德的沦丧?

冲着async/await支持,笔者最近在一个小项目中试用了Rust v1.39。虽然只是个小工程,写完后深刻体会都了Rust无与伦比的优势。

1.决不妥协 —— 兼顾性能与安全性

几十年以来,C/C++一直都是操作系统内核、浏览器、NGINX、Redis等这类性能关键(Performance Critical)软件开发的首选语言。但存在的问题也非常明显:空指针、野指针、内存越界等。轻则Segment Fault崩溃,重则导致难以发现的0-day漏洞。

寄希望于开发人员不犯一丁点错误写出内存安全的软件无异于痴人说梦。因此自90年代开始,以Java为代表的一系列自动化内存管理的编程语言兴起。通过在性能方面做出适当的妥协和让步,引入GC等机制,来实现内存安全。

从此,软件开发常常面临这样的两难选择:要么为了安全性而在性能上做出妥协;要么为了极致的性能牺牲安全性。例如在使用Java开发某网络服务时,为了实现zero-copy转发,JVM管理的byte[]已经无法满足要求,需要使用不受GC管理的Direct Buffer。比如采用netty.io中引用计数管理的ByteBuf ,使用时慎之又慎,否则非常容易导致内存泄漏或者内存提前释放,特别是加上逻辑分支异常处理的情况下这些错误难免出现。从那时起,在性能与安全性的选择上似乎就变成了“鱼与熊掌不可兼得”的难题。

“鱼与熊掌不可兼得”的难题

而Rust在设计之初就设定了必须同时兼顾性能和安全性的目标——既要有"底层语言"一样的性能,又要有"高层语言"的安全性(甚至在线程安全性方面比Java/C#等语言更加安全!)。这样一种决不妥协的设计哲学,让Rust从一出生开始就注定了它的不平凡。

Rust兼顾“低层”和“高层”语言的特性

1.1 内存安全性

Rust没有传统的垃圾回收器。为了解决内存安全性,Rust独创了所有权(Onwership)系统与租借检查器(Borrow Checker)。

比如下面的代码

s 是一个referent,它指向内存中的一个字符串对象。编译器编译代码时候,会在referent的作用域范围结束位置自动生成代码销毁所指的内存对象。即referent拥有着此内存对象的所有权。所有权也能够从一个referent转移到另一个referent,亦即所有权转移(move)。无论怎么转移,对于内存中的某个对象在同一时间内有且仅有一个referent获得了它的所有权。听上去referent有点像C++中的auto_ptr智能指针,但Rust的referent更加细腻和强大。

b1/b2/b3看上去很像指针,在Rust中它们被称为租借(borrow)。

  • 其中b1是可变(mutable)租借,而b2/b3 属于不可变(immutable)租借。
  • 在同一时间内,一个referent可以有多个不可变租借或者一个可变租借,这点类似于读写锁(Readers-Writer lock);
  • 租借的作用域不能超过其referent作用域,以此防止野指针的出现。
  • referent和borrow都没有空值,因此杜绝了空指针。
  • 多个对象之间的borrow不能出现闭环(相互引用或者循环引用),极大地避免隐式内存泄漏。

关于referent和borrow的详细规则可见下图(原图地址)。

所有的这些规则都由编译器实现。简而言之,Rust通过编译期的规则实现了没有GC下的内存安全。

1.2 线程安全性

在内存安全的基础上,Rust更进一步地保证了线程安全性。

  • 默认情况下一个对象只能被拥有所有权的线程访问。
  • 实现了Send trait的数据类型所有权能够在多个线程间转移,但线程间不存在共享数据。
  • 实现了Sync trait的数据类型能够被多个线程同时访问,代表着该数据类型实现了线程间的同步操作。

需要说明的是,SendSync都属于编译器自动添加的标记(marker trait),并不需要开发人员实现。如果某个数据类型所有成员都是SendSync的,那么该数据类型也会被自动标记为SendSync。这样如果代码能够编译通过就自然而然地说明线程安全。

1.3 性能

benchmark显示Rust有着媲美C/C++的效率,就执行速度而言狂虐Golang/Java。

TechEmpower进行的主流Web框架性能测试中,由微软员工Kim使用Rust构建的actix开源框架在多项测试场景中拔得头筹。

依据历年的数据,70%的安全漏洞都和内存安全有关。Rust完美解决了安全性和性能的两难问题,也让它成为了开发底层应用的更优选择。目前,Intel微软Linux都在积极准备使用Rust开发驱动程序甚至操作系统内核以改善日益严峻的安全问题。

近年来CVE中内存安全类漏洞比例图

2.兼容并包 —— 支持多种编程范式

Rust在设计之初被定位为多范式语言(multi-paradigm language),在汲取了其它语言大量成功经验基础上,并不限定用户采用某种特定的范式。

2.1 命令式风格与函数式风格

Rust支持传统的命令式风格(imperative style)代码无须赘述。Rust同时也吸取了大量ML阵营函数式风格(functional style)编程语言的诸多特性,比如模式匹配、不可变量与无副作用方法、Haskell类型系统、反向类型推导和trait特性系统等。这使Rust拥有极致的性能和对底层细腻的掌控能力的同时,具备高度抽象的表达能力。

2.2 多线程模型

使用Rust进行多线程应用开发,同样拥有极高的自由度。

  • 可以选择线程间共享数据,通过传统的操作系统原语同步或者lockless数据结构;
  • 也可以选择CSP(Communicating sequential processes)模型,就如Golang开发手册中总结的那样“Do not communicate by sharing memory; instead, share memory by communicating.”。
  • 还可以选择如Erlang那样的异步Actor模型

3 v1.39添加了async/await 异步编程支持

对于高并发I/O应用的开发,异步编程是首选项。传统的异步依赖于回调或者闭包,实现起来麻烦不说,代码可读性也差强人意。而Rust这次新添加的两个关键字类似于C#和Python中的async / await ,用户无需再依赖于回调或者闭包,用最自然的方式编写可读性佳的I/O操作代码,代码看上去和同步代码无异,而编译器将异步调用部分编译为状态机从而实现异步执行。这点感觉非常好。

4.个人使用体会

Rust学习曲线略为陡峭,突破新手期所需时间数倍于Golang/Python,如果有着C++和Haskell经验对这一阶段帮助很大。突破新手期后就一片坦途,不再像编写C/C++程序那样谨小慎微,而async/await关键字的引入大大方便了异步编程,很多时候感觉都在用C#/Java这样的高层语言编程一样--关注于业务和程序结构而不用去担心某个对象错误地释放。

需要吐槽的是各自为战的生态系统,为了熟练使用async/await关键字,关于future就需要知晓std::future::Future 和futures::future::Future, 而后者还分为0.1版本和0.3版本。又由于不同的库依赖于不同的future实现,所以还需要精通它们之间各种转换,开始时真有点头大╮(﹀_﹀)╭。

瑕不掩瑜。Rust可以说是目前最全面的编程语言。它既可以用于开发与硬件打交道的底层,也能用来开发对性能有极致要求的微服务,甚至还可以开发运行在浏览器中的WebAssembly网站。在拥有极致性能的同时又不失鲁棒性和安全性。编程风格自由且高效,能够被广泛的其它语言开发者(C++/Haskell/Python/Scala等)接纳。这些优势决定了Rust将会大放异彩!

最后来一段使用Seed开发的WebAssembly浏览器页面代码展示:

fn view(model: &Model) -> impl View<Msg> {
let plural = if model.count == 1 {""} else {"s"}; // Attrs, Style, Events, and children may be defined separately.
let outer_style = style!{
St::Display => "flex";
St::FlexDirection => "column";
St::TextAlign => "center"
}; div![ outer_style,
h1![ "The Grand Total" ],
div![
style!{
// Example of conditional logic in a style.
St::Color => if model.count > 4 {"purple"} else {"gray"};
St::Border => "2px solid #004422";
St::Padding => unit!(20, px);
},
// We can use normal Rust code and comments in the view.
h3![ format!("{} {}{} so far", model.count, model.what_we_count, plural) ],
button![ simple_ev(Ev::Click, Msg::Increment), "+" ],
button![ simple_ev(Ev::Click, Msg::Decrement), "-" ], // Optionally-displaying an element
if model.count >= 10 { h2![ style!{St::Padding => px(50)}, "Nice!" ] } else { empty![] }
],
success_level(model.count), // Incorporating a separate component h3![ "What are we counting?" ],
input![ attrs!{At::Value => model.what_we_count}, input_ev(Ev::Input, Msg::ChangeWWC) ]
]
} #[wasm_bindgen(start)]
pub fn render() {
seed::App::build(|_, _| Init::new(Model::default()), update, view)
.build_and_start();
}

 

Rust v1.39发布 - 这个编程语言真不一般!的更多相关文章

  1. 亿能测试白盒安全测试模板V1.0发布

    亿能测试白盒安全测试模板V1.0发布http://automationqa.com/forum.php?mod=viewthread&tid=2911&fromuid=21

  2. RDIFramework.NET平台代码生成器V1.0发布(提供下载)

    RDIFramework.NET平台代码生成器V1.0发布(提供下载)   RDIFramework.NET(.NET快速开发整合框架)框架做为信息化系统快速开发.整合的框架,其目的一至是给用户和开发 ...

  3. 启明星手机版安卓android会议室预定系统 V1.0发布

    启明星手机版会议室预定系统 V1.0发布 在手机里输入 http://www.dotnetcms.org/e4.apk 或者扫描二维码下载 用户打开系统,可以实时查看所有会议室状态 点击会议室名称,可 ...

  4. 手脱EXE32Pack v1.39

    1.PEID查壳 EXE32Pack v1.39 2.载入OD,先F8跟一下 0040A00C > 3BC0 cmp eax,eax ; //程序入口点 0040A00E je short st ...

  5. Kubernetes v1.16 发布 | 云原生生态周报 Vol. 20

    作者:心贵.进超.元毅.心水.衷源.洗兵 业界要闻 Kubernetes v1.16 发布 在这次发布中值得关注的一些特性和 Feature: CRD 正式进入 GA 阶段: Admission We ...

  6. Delphi MlSkin V1.1 发布啦! 它能让你的程序拥有像QQ一样多彩炫丽的外观!

    http://bbs.csdn.net/topics/390740239 本帖最后由 u014161811 于 2014-03-24 09:46:40 编辑 QQ皮肤透明TEdit透明TMemo图片按 ...

  7. 国产编程语言R++ V1.5发布

    R++ v1.5内核改动较大,下面是一些主要变化: 1.使用PJIT(Pseudocode Just-In-Time),编译速度大幅提高,但运行效率远远不如C++,不过R++将在下一版本支持RJIT( ...

  8. ComponentOne Studio for Enterprise 2015 v1 全新发布

    ComponentOne Studio 即将发布2015年的第一个版本.2015 v1版本聚焦于优化性能.提升数据可视化能力.加强数据管理以及更人性的输入方式及报表解决方案. 免费下载试用 WinFo ...

  9. 物联网操作系统Hello China移植mile stone之一:移植基础版本V1.76发布

    Hello China V1.76版发布,这是向ARM系列CPU移植的基础版本.相对V1.75版,该版本主要做了如下的一些调整: 1.  通过宏定义的方式对内核实现了模块化,开发者可以通过开启或关闭预 ...

随机推荐

  1. 3.java基础之关键字instanceof

    1. instanceof 使用:对象引用名 instanceof 类名 作用:来判读引用的对象和类名是否兼容(是否继承该类,或爷爷辈的类) 例子: Team team = new Team(); t ...

  2. python实现智能语音天气预报

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: 飞奔的帅帅 PS:如有需要Python学习资料的小伙伴可以加点击下 ...

  3. [转]RPA Developer Advanced Certification - Exam #1 UiPath 练习

    本文转自:https://github.com/miyaichi/CertificationExam1 RPA Developer Advanced Certification - Exam #1 E ...

  4. Python Exception处理

    Python中的错误处理分为两类:语法错误和异常处理.语法错误一般是指由于python语句.表达式.函数等存在书写格式活语法规则上的错误抛出的异常,如python常见的缩进控制,若同层次的执行语句存在 ...

  5. Centos8 配置静态IP

    安装centos 8之后,重启启动网络时,会出现以下报错 报错信息如下: Failed to start network.service: Unit network.service not found ...

  6. Java IO系列之 ByteArrayInputStream

    http://www.cnblogs.com/skywang12345/p/io_02.html

  7. java8-计算时间差的方法

    一.简述 在Java8中,我们可以使用以下类来计算日期时间差异: 1.Period 2.Duration 3.ChronoUnit 二.Period类 主要是Period类方法getYears(),g ...

  8. javascript es6 Promise 异步同步的写法(史上最简单的教程了)

    1 来个简单的例子 var p = new Promise(function(resolve, reject){ //做一些异步操作 setTimeout(function(){ console.lo ...

  9. 了解Github

    一.什么是Github Github是全球最大的社交编程及代码托管网站(https://github.com/). Github可以托管各种git库,并提供一个web界面(用户名.github.io/ ...

  10. C++笔记——快读快写

    直接开始吧 额m~,这里就没什么好说的了,无非就是用getchar加快cin或printf的读入速度. 代码: inline int read() { int X=0; bool flag = 1; ...