专栏首页Rust学习专栏那些必须要了解的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的项目

  1. 修改Cargo.toml

vi Cargo.toml

在依赖处添加以下内容

[dependencies]
tokio = { version = "1", features = ["full"] }
  1. 修改源代码

vi src/main.rs

并将代码替换为以下内容

async fn say_word() {
    println!("my tokio");
}
#[tokio::main]
async fn main() {
    let op = say_word();
    println!("hello");
    op.await;
}
  1. 编译并执行

cargo build

cargo run

结果如下:

Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/my-tokio`
hello
my 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));
 }

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

上面的代码就是建立Tcp连接,发送数据,最后读取返回,每个Future都是通过and_then建立关系,而future机制精髓之处在于,整个过程是通过core.run(response).unwrap();这行代码运行起来的,也就是说在Future的帮助下,程序员只需要关心最终的结果就可以了,整个链条通过poll机制串联,从poll机制来看,这几个模块的传递机制如下:

从建立网络连接开始的调用链交给计算机去帮你完成,不但省去了回调所带来的复杂性,最终的效率反而还会更高。

poll模制到底是什么意思?

笔者看到不少博主在介绍Rust的Future等异步编程框架时都提到了Rust的Future采用poll模式,不过到底什么是poll模式却大多语焉不详,其实poll做的本质工作就是监测链条上前续Future的执行状态。

以上述情况为例,poll的方向是由response到request最后是socket,但是state和data的返回方向是完全返过来的,也就是说response通过poll来获取request的state,而request也同样通过poll来获取socket的state。

笔者还是这样的观点,程序员群体之所以觉得future机制难以理解,其关键在于思维模式被计算机的各种回调机制给束缚住了,而忘记了最简单直接的方式。在解决这个问题之前我们先来问一个问题,假如让我们自己设计一个类似于tokio这样的异步Future管理器,应该如何入手?

最直接也是最容易想到的方案就是事件循环,定期遍历整个事件队列,把状态是ready的事件通知给对应的处理程序,这也是我们常说的select方案;另外一种做法是在事件poll管理器中直接拿到处理程序的句柄,不再遍历整个事件队列,而是直接在中断处理响应中把通知发给对应处理进程,比如上述例子中实际是按照poll的链条传递的处理进程句柄的,这就是Poll模式。而基于poll设计的如tokio框架进行应用开发时,程序员根本不必关心整个消息传递,只需要用and_then、spawn等方法建立链条并让系统工作起来就可以了。

而epoll(多路复用)是基于poll的另一种高并发机制,这种机制可以监视多个描述符,一旦某个描述符状态变为就绪,能够通知对应的handler进行后续操作。笔者在前文《这位创造了Github冠军项目的老男人,堪称10倍程序员本尊》中曾经介绍过Tdengine的定时器,其中就有这种多路复用的思想。由于操作系统timer的处理程序还不支持epoll的多路复用,因此每注册一个timer就必须要启动一个线程进行处理,资源浪费严重,因此Tdengine自己实现了一个多路复用的timer,可以做到一个线程同时处理多个timer,这些细节上的精巧设计也是Tdengine封神的原因之一。

后记

写到这突然发现tokio框架的介绍一篇文章根本就不可能完成,那么本文权当一个基础介绍,为入门tokio做准备,如果后面读者们再有强烈需求,我们再继续聊这个话题。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Rust高并发编程总结

    Serverless的概念火了,业界已经不再讨论要不要用Serverless的问题了,而是高喊Serverless First的口号力求快速拥抱Serverle...

    beyondma
  • 【大家的项目】Rbatis - 制作 Rust 语言堪比 Mybatis 的异步 ORM 框架

    因为是复刻Java系的Mybatis,因此框架暂命名 Rbatis。小部分功能还在进行中。github链接https://github.com/rbatis/r...

    MikeLoveRust
  • Rust网络编程框架-Tokio进阶

    我们在上文《小朋友也能听懂的Rust网络编程框架知识-Tokio基础篇》对于Tokio的基础知识进行了一下初步的介绍,本文就对于Tokio的用法及原理进行进一步...

    beyondma
  • 【Rust日报】 2019-07-17:微软安全响应中心:一种主动性的方式来提升安全

    本文简单介绍了在Rust中编写一个工程性更强的组件(crate)所必须要遵循的一些原则:

    MikeLoveRust
  • 【Rust日报】2021-02-21 Ballista:在Rust中实现的分布式计算平台

    Ballista-0.4.0 已于昨天发布。Ballista是主要在Rust中实现的分布式计算平台,由Apache Arrow支持。

    MikeLoveRust
  • Rust的第二次接触-写个小服务器程序

    蛮久前入门了一下 Rust 语言。它的设计模型非常地吸引C/C++的开发者。但是学习语言嘛还是要练习一下,之前也用它给我们项目写了个命令行小工具。这回拿来写个小...

    owent
  • Rust 不适合开发 Web API

    Rust 是一门神奇的编程语言,有非常好的 CLI 工具,比如 ripgrep 和 exa。像 Cloudflare 这样的公司正在使用并鼓励人们写 Rust ...

    深度学习与Python
  • Linkerd最先进的Rust代理|Linkerd2-proxy

    部分由于Linkerd的性能数字和一流的安全审计报告,最近对Linkerd2-proxy(Linkerd使用的底层代理)的兴趣激增。作为一名Linkerd2维护...

    CNCF
  • Rust 与 Wasm 在 Serverless AI 推理函数中的作用

    公有云中的 Serverless TensorFlow 函数 对于软件开发者和学生来说,人工智能是有偿的。2021年,最流行的 AI 框架 Tensorflo...

    腾讯云serverless团队
  • 【Rust日报】 2019-08-12:Tokio alpha 版发布,新版本支持async/await

    Read More: https://tokio.rs/blog/2019-08-alphas/

    MikeLoveRust
  • Rust 视界 | async-std 团队发布 Async Http 套件

    本文是对Yoshua Wuyts 博客文章的摘录,以及一些私人观点。原文地址:https://blog.yoshuawuyts.com/async-http/ ...

    MikeLoveRust
  • 【Rust日报】 2019-08-11:C++工程师的Rust迁移之道 组合与集成

    对于上述提到的3个问题,在Rust中有一个统一的解决方案,那就是trait系统, 更多内容请看正文。

    MikeLoveRust
  • 【Rust日报】 2019-07-16:「新手向」Rust vs C++ : 实现神经网络

    该站点专注于记录世界各地Rust各大活动的时间线,开源项目,大家可以提交活动信息。

    MikeLoveRust
  • Rust网络编程框架-深入理解Tokio中的管道

    我们在上文《Rust网络编程框架-Tokio进阶》介绍了async/await和锁的基本用法,并完成了一个Server端的DEMO代码。本文继续来探讨这个话题。

    beyondma
  • 基于腾讯云的 Rust 和 WebAssembly 函数即服务

    腾讯云云函数 (SCF) 已经支持十多种编程语言和运行时框架。腾讯云最近发布的 SCF custom runtime(自定义运行时)更进一步 —— SCF 现...

    腾讯云serverless团队
  • 【Rust日报】2021-04-09 tokio 计划发布基于 io-uring 的新运行时

    tokio 今天发布了新的 RFC,提出了新的支持 io-uring 异步运行时的计划。

    MikeLoveRust
  • 【Rust日报】 2019-05-01:Rust和Windows不得不说的事儿

    ralfj比较高产,他负责Unsafe下内存模型相关的工作,目的是用miri来检测unsafe中的UB行为。

    MikeLoveRust
  • 【Rust日报】2021-01-16 Async-std v1.9.0 发布

    webrtc.rs,用 Rust 重写 Pion WebRTC (http://Pion.ly)。目前 v1.0 仍然处于开发中,欢迎开源贡献者提PR。其路线图...

    MikeLoveRust
  • 【Rust日报】2020-06-09 - 《用Rust语言开发自己的编程语言》

    免费网络书: 《用Rust语言开发自己的编程语言》。展现rust语言的强大和神奇魅力!

    MikeLoveRust

扫码关注云+社区

领取腾讯云代金券