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. [转]UiPath Build Data Table

    本文转自:https://docs.uipath.com/activities/docs/build-data-table UiPath.Core.Activities.BuildDataTable ...

  2. Git问题汇总

    1.fatal: refusing to merge unrelated histories $git pull origin master --allow-unrelated-histories 2 ...

  3. MongoDB用户验证和权限管理

    官方参考页面: https://docs.mongodb.com/v3.6/tutorial/enable-authentication/ https://docs.mongodb.com/v3.6/ ...

  4. 初级模拟电路:4-1 BJT交流分析概述

    回到目录 BJT晶体管的交流分析(也叫小信号分析)是模拟电路中的一个难点,也可以说是模电中的一个分水岭.如果你能够把BJT交流分析的原理全都搞懂,那之后的学习就是一马平川了.后面的大部分内容,诸如:场 ...

  5. 附007.Kubernetes ABAC授权

    一 ABAC 1.1 ABAC授权 基于属性的访问控制(ABAC)定义了访问控制范例,通过使用将属性组合在一起的策略向用户授予访问权限. 使用--authorization-policy-file=S ...

  6. 如何将pyqt5的qt-designer设计出来的 .ui 和 .qrc 文件转化成 .py 文件

    一.pyrcc5的使用 1.1 作用 将 .qrc 资源文件转换成py文件,并在主程序中通过 import 引入 1.2 资源文件编写说明 创建一个icon.qrc,代码如下: <RCC> ...

  7. 新入手的Mac,该如何设置?

    如果您入手了一台Mac.设置Mac的过程直观且易于执行,但是如果您是新手,可能会遇到有一些小麻烦.没关系,本篇文章小编将帮助您设置Mac,让您像专业人士一样迅速运转您的Mac. 设置前提 在开始设置全 ...

  8. laravel5+ElasticSearch+go-mysql-elasticsearch MySQL数据实时导入(mac)

    1. ElasticSearch安装 直接使用brew install elasticsearch 安装最新版本的es,基本没有障碍. 2.Laravel5 框架添加elasticsearch支持 在 ...

  9. fjnu2019第二次友谊赛 B题

    ### 题目链接 ### 题目大意: 给你一个 n * m 的地图以及小蛇蛇头的初始位置,告诉你它会往 上.下.左.右 四个方向走.若在走的过程中(包括结束时)会使得小蛇越界,则输出 "Ga ...

  10. 用二进制写程序,提升装 X 境界

    用二进制来写程序这么反人类的事情,的确是很装的事情,但是它不但是一件很装的事情,也是掌握底层知识的基础能力之一.听我慢慢道来. 程序设计语言有高级语言和低级语言之分,尤其是现在各种编程语言的不断发展, ...