Serverless时代的并发神器-Rust语言Tokio框架基础

发布时间:2021年11月13日 阅读:520 次

Serverless时代的并发神器-Rust语言Tokio框架基础

Serverless时代的并发神器-Rust语言Tokio框架基础

那些必须要了解的Serverless时代的并发神器-Rust语言Tokio框架基础

今天我们继续高并发的话题,传统的云计算技术,本质上都是基于虚拟机的,云平台可以将一些性能强劲的物理服务器,拆分成若干个虚拟机,提供给用户使用,但在互联网发展到今天,虚拟机还是太重了。即使是飞天集群,新增部署虚拟机的时间也是以分钟来计的。但是对于互联网用户来讲20秒的等等就是就会千万50%以上的用户流失,不能忍受的煎熬,因此Docker秒级启动的速度也不是个完美的解决方案,最终还是要Serverless极速的伸缩才能满足客户需求。

通俗的讲,Serverless就是基建狂魔版的云平台,虽然传统的基建技术安全性更高,稳定性也更好,但是从头修路、盖房、装修成本太高时间也太长,而Serverless本质上是一个比容器还小的最小运行环境的镜像,只要给点阳光就能野灿烂,而且用完以后想拆也很方便,是应对云原生时代最新发展出的神器。

在我之前的博客中也不止一次提到,在Serverless时代,服务冷启动的速度与服务内存的消耗都是决定成败的关键。无GC更不依赖JVM的Rust无论在冷启速度还是在内存消耗上都比JAVA和GO更具优势,而且相比C语言Rust的生产效率也更高,很多储如从函数式语言借鉴而来的Future机制都非常先进,根据官方的测试结果,在性能方面Rust的网络编程框架比JAVA和GO要好得多

但是我意外的看到像Rust中Tokio这样优秀的高并发网络编程框架在中文技术社区却没有个完整的教程,因此笔者决定将这段时间探索Tokio的心得向大家分享一下,

初识Tokio

Tokio是基于Rust开发的异地网络编程框架,用于执行异步代码的多线程运行时。通过Future、async/await等机制,开发者可以让代码产生极高生产力的同时保持程序的性能基本与C语言一致,基于Tokio的开发在编写异步代码时,开发者不能使用Rust标准库提供的阻塞api,而必须使用由Tokio提供,镜像了Rust标准库的API。我们先来看一个Tokio的Helloworld程序

1.首先创建项目

cargo new my-tokio

命令创建一个my-tokio的项目

2. 修改Cargo.toml

vi Cargo.toml

在依赖处添加以下内容

[dependencies]

tokio = { version = "1", features = ["full"] }

3. 修改源代码

vi src/main.rs 

并将代码替换为以下内容

async fn say_word() {

    println!("my tokio");

}

#[tokio::main]

async fn main() {

    let op = say_word();

    println!("hello");

    op.await;

}

4. 编译并执行

cargo build

cargo run

结果如下:


    Finished dev [unoptimized + debuginfo] target(s) in 0.02s

     Running `target/debug/my-tokio`

hello

my tokio

Serverless时代的并发神器-Rust语言Tokio框架基础

这里我们先解释一下async和await的用法,我们看到async fn say_word()中,say_word()函数是被async关键词修饰的,那么也就是说这个函数在被调用时 let op = say_word();

,以上代码是被立即返回而没有被执行的,而这时op实际是一个Future,也就是一个现在为空,在未来才会产生的值(有关Future的机制我们接下来解释),而在调用op.await的时其实是在等到这个async异步操作执行完毕才返回,是一个阻塞操作,因此最终输出会是先打印hello,然后再打印my tokio

程序员如何理解更像自然语言的Future

在以下这段代码中,网络连接socket、请求发送request、响应接收response三个对象全部都是future类型的,也就是在代码执行之后不会被执行也没有值仅有占位的意义,当未来执行后才会有值返回,and_then方法其实是在future对象执行成功后才会被调用的方法,比如read_to_end这行代码就是在request对象执行成功后,调用read_to_end方法对读取结果。

use futures::Future;

use tokio_core::reactor::Core;

use tokio_core::net::TcpStream;fn main() {

    let mut core = Core::new().unwrap();

     let addr = "127.0.0.1:8080".to_socket_addrs().unwrap().next().unwrap();

     let socket = TcpStream::connect(&addr, &core.handle());

 

     let request = socket.and_then(|socket|{

         tokio_core::io::write_all(socket, "Hello World".as_bytes())

     });

     let response = request.and_then(|(socket, _)| {

         tokio_core::io::read_to_end(socket, Vec::new())

     });

 

     let (_, data) = core.run(response).unwrap();

     println!("{}", String::from_utf8_lossy(&data));

 }

而想象一下如果是传统编程所采用的方式,需要在网络连接完成后调用请求发送的回调函数,然后再请求发送的响应处理方法中再注册接收请求的回调函数,复杂不说还容易出错。


Tag:Serverless 时代 神器 语言 Tokio 框架 基础
相关文章

发表评论: