rust 手动关闭子线程_深入浅出Rust异步编程之Tokio

本文以tokio为例简单介绍Rust异步编程相关的一些知识。

首先让我们看看为什么使用rust来进行异步编程。这里tokio官方给出了一个性能测试的对比,可以看到tokio是性能最好,实际上运行这个基准测试的时候,tokio性能更好的2.0版本尚未发布,否则估计性能还有很大提升。因此,我们可以认为需要非常极致性能的时候,我们可以选择rust+tokio来实现。

f10545abc8ddbd3368bd14da163ff3b6.png

Rust网络编程

Rust实际上并不跟一定的网络编程模型强绑定,实际rust可以实现阻塞IO+多线程,非阻塞IO+回调,用户态线程等多种模型。这里着重介绍Rust实现的用户态线程。

  • 首先,Rust的用户态线程是一种基于Future的用户态线程,关于Future本身,本文后续部分有详细论述。

  • 其次,由于是Rust实现,因此可以做到零成本抽象,并且更容易做到安全。

  • 最后,由于没有运行时大量内存分配,没有动态逻辑分派,也没有GC开销,所以该实现的效率非常高。

Rust异步编程是构建在操作系统相关API上,MIO库类似Java的Nio库,针对多种操作系统的不同API做了统一封装。Future库类似Java的Future库,提供了相关接口和常用的组合能力。Tokio构建于两者之上,在MIO和future的基础上实现了用户态线程。使用Tokio进行异步编程的技术栈如下,需要注意的是,应用程序会同时接触到Tokio和future的API。

6eafbb953a254c9f10ef92fd4a0ccee8.png

Futures

future是rust异步编程的核心。首先我们介绍什么是future。future是一段异步计算程序,可以在将来获取产生的数据。举例来说,获取数据库查询结果,RPC调用这些实际上都可以使用future来实现。通常实现future有两种模式,一种基于推模式,也被称为基于完成的模式,一种基于拉模式,也被称为基于就绪的模式。Rust的future库实现了基于拉模式的future。

rust的future选择拉模式来实现。接口定义如下:

pub trait Future { type Item; type Error; fn poll(&mut self) -> Poll<:item self::error>;}
假设一个future要做这样的功能,从TCP数据流读取数据并计算自己读了多少个字节并进行回调。那用代码表示:
struct MyTcpStream { socket: TcpStream, nread: u64,}impl Future for MyTcpStream { type Item =u64; type Error = io::Error; fn poll(&mut self) -> Poll { let mut buf = [0;10]; loop { match self.socket.read(&mut buf) { Async::Ready(0) => return Async::Ready(self.nread), Async::Ready(n) => self.nread += n, Async::NotReady => return Async::NotReady, } } }}

每次调用poll方法,MyTcpStream都会调用socket的read方法(这里的TcpStream本身也是一个future,read内部也是调用poll方法),当read返回为Async::NotReady的时候,调度器会将当前的Task休眠,如果返回Async::Read(n)表示读到了数据,则给计数器加对应的数,如果返回Async::Ready(0),则表示TcpStream里有的数据已经读完,就将计数器返回。

为了方便大家使用,future库包提供了很多组合子,以AndThen组合子为例:

enum AndThen { First(A, F),}fn poll(&mut self) -> Async { match fut_a.poll { Async::Ready(v) => Async::Ready(f(v)), Async::NotReady => Async::NotReady, }}

这里AndThen枚举,First有两个值,其中A是一个future,F是一个闭包,AndThen实现的poll方法,就是假如调用future_a的poll方法有返回值,那么就调用闭包,并将其返回值包装为Async::Ready返回,如果poll的返回值是Async::NotReady则同样返回Async::NotReady。有了这个AndThen方法,通过组合子函数(比如and_then实际上是将上一个future和闭包传入生成一个AndThen future),我们就可以实现一些复杂逻辑:

let f=MyTcpStream::connect(&remote_addr) .and_then(|num| {println!("already read %d
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值