首页 > 其他分享 >async-await Rust: 200 多行代码实现一个极简 runtime

async-await Rust: 200 多行代码实现一个极简 runtime

时间:2023-07-12 16:55:35浏览次数:45  
标签:200 task NonNull 极简 await let duration runtime struct

What I cannot create, I do not understand

Rust 中的 runtime 到底是咋回事, 为了彻底搞懂它, 我在尽量不借助第三方 crate 的情况下实现了一个玩具 runtime, 之所以说是玩具,因为它没有复杂的调度算法(只有一个全局 task queue)

代码除了 mpmc(multi-producer, multi-consumer) 使用第三方 crate crossbeam 之外, 其余代码一律手撸

可以这么玩

fn main() {
    let toy = Toy::new();

    for i in 1..=20 {
        toy.spawn(async move {
            let ret = FakeIO::new(Duration::from_secs(i)).await;
            println!("{:?}: {:?}", thread::current().id(), ret);
        })
    }

    toy.run(4); // 4 threads
}

其中 FakeIO 也是足够单纯

pub struct FakeIO {
    finished: Arc<AtomicBool>,
    duration: Duration,
}

impl Future for FakeIO {
    type Output = Duration;

    fn poll(
        self: std::pin::Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<Self::Output> {
        if self.finished.load(Ordering::Acquire) {
            return Poll::Ready(self.duration);
        }

        let finished = self.finished.clone();
        let waker = cx.waker().clone();
        let duration = self.duration;

        thread::spawn(move || {
            thread::sleep(duration);

            finished.store(true, Ordering::Release);

            waker.wake();
        });

        Poll::Pending
    }
}

数据结构

数据结构就下面几个(参考了 tokio 的设计)

struct Task {
    raw: RawTask,
}

unsafe impl Send for Task {}
unsafe impl Sync for Task {}

struct RawTask {
    ptr: NonNull<Header>, // pointer to Cell<T> where T: Future
}

struct Header {
    // todo: maybe replace the Mutex<State> with AtomicUsize
    state: Mutex<State>,
    vtable: &'static Vtable,
    sender: crossbeam::channel::Sender<Task>,
}

#[derive(Default)]
struct State {
    running: bool,
    notified: bool,
    completed: bool,
}

/// #[repr(C)] make sure `*mut Cell<T>` can cast to valid `*mut Header`, and backwards. 
/// In the default situation, the data layout may not be the same as the order in which the fields are specified in the declaration of the type
/// 默认情况下 Rust 的数据布局不一定会按照 field 的声明顺序排列
/// [The Default Representation](https://doc.rust-lang.org/reference/type-layout.html?#the-default-representation)
///
/// [playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=39ac84782d121970598b91201b168f82)
/// 
/// you can easilly view the data layout with this crate https://github.com/hangj/layout-rs
#[repr(C)]
struct Cell<T: Future> {
    header: Header,
    future: T,
    output: Option<T::Output>,
}

struct Vtable {
    poll_task: unsafe fn(NonNull<Header>),
    clone_task: unsafe fn(NonNull<Header>) -> NonNull<Header>,
    drop_task: unsafe fn(NonNull<Header>),
}

其中值得注意的是:

  • RawTask 内的 ptr 实际上指向的是 NonNull<Cell<T: Future>>
  • Cell<T: Future> 被标记了 #repr(C), 原因已在注释中说明
  • vtable 的设计参考了 Waker 中的 vtable, 相当于利用泛型函数保存了类型信息, 便于后面从裸指针恢复到原始类型

点击「阅读原文」直达 toy-runtime 仓库

Have fun!

标签:200,task,NonNull,极简,await,let,duration,runtime,struct
From: https://www.cnblogs.com/hangj/p/17547958.html

相关文章

  • plc200转以太网在建材矿粉磨系统中的应用案例
    内容摘要上位机与S7-300PLC通信采用以太网通信,通讯模块采用捷米特ETH-S7300-JM01以太网通讯模块,捷米特ETH-S7300-JM01通讯模块直接插到CPU315-2DP的DP口上。 项目介绍立磨PLC控制系统:立磨是一种理想的大型粉磨设备,广泛应用于水泥、电力、冶金、化工、非金属矿等行业。它集......
  • 《安富莱嵌入式周报》第317期:开源60W小型UPS电源,0.1Hz - 200MHz 频率计,纯C实现的Sokol
    周报汇总地址:http://www.armbbs.cn/forum.php?mod=forumdisplay&fid=12&filter=typeid&typeid=104  视频版:https://www.bilibili.com/video/BV1Mx4y1o7Ns 1、开源60W小型UPS电源参考设计https://github.com/TobleMiner/DC-UPShttps://github.com/TobleMiner/dc-ups-......
  • 西门子S7-200西门子700iev3以太网传输
    方案摘要:西门子S7200系列PLC通过MatrikonOPC实现以太网连接,捷米特ETH-S7200-JM01以太网模块为PLC200转换出以太网通讯接口。 功能简介MatrikonOPC是世界上最大的OPC开发商和供应商,我们的产品涵盖了OPC服务器、客户端、应用程序、OPC工具等。我们更是全球范围内最大的OP......
  • 西门子200转以太网模块300plc以太网上传程序
    内容摘要大家好,今天我们要为大家介绍一款神奇的设备——捷米特ETH-S7200-JM01以太网模块!它可以让西门子PLC200CPU226拥有以太网通讯接口,实现数据采集和生产管理系统构建。你以为这就是它的全部功能?那你就大错特错了! 除了实现以太网通讯,捷米特ETH-S7200-JM01还有其他神奇的功......
  • 洛谷 P6109 - [Ynoi2009] rprmq1
    首先将修改操作差分为\(l_1\)时刻给\([l_2,r_2]\)中的值\(+v\),\(r_1+1\)时刻给\([l_2,r_2]\)中的值\(-v\)。这样第\(i\)行的状态相当于执行\(1\simi\)时刻的操作后的状态。猫树分治,把一个询问挂在线段树上满足\(l\lel_1\lemid\ler_1\ler\)的区间\([l,r]\)......
  • P2024 [NOI2001] 食物链 || #576. 食物链【NOI2001】 (并查集)
    空降锣鼓空降OJ题解:#include<bits/stdc++.h>usingnamespacestd;intn,k;intd,x,y;intans;intfa[500050];intfind(intx){//找爸爸 if(fa[x]==x) returnfa[x]; returnfind(fa[x]);}intmain(){ cin>>n>>k; for(inti=1;i<=n*3;i++)//开三个并查集风......
  • MPI以太网通讯处理器西门子 plc s7 200以太网接口
    在热处理行业,铝型材时效炉是一款至关重要的设备,它不仅要求设备稳定性高,温度均匀性也必须达到最佳状态。然而,传统的以太网通迅CP343处理器在电气控制系统中的应用成本却非常高。那么,有没有一种更加性价比的替代方案呢?  捷米特研发的ETH-S7300-JM01以太网通讯处理器就是这样一......
  • 西门子水处理1200PLC程序+触摸屏程序,博图V16学习程序,可仿真实验
    西门子水处理1200PLC程序+触摸屏程序,博图V16学习程序,可仿真实验Plc程序包含功能块,功能块为SCL编写,内含模拟量换算功能块+滤波功能块+时间换算功能块+modubustcp通讯程序有原理图有PLC程序有HMI程序ID:699656358081870......
  • labview与西门子1200 S7通信 PLC不用写通信程序,上位机直接读
    labview与西门子1200S7通信PLC不用写通信程序,上位机直接读写DB块,不是调用DLL,labviewS7协议,简单好用YID:6930654641311183......
  • M1 安装redis 报错问题 {assert {[r memory usage key] < 42000}} proc ::test)
    macm1安装redis基本步骤官方下载安装包https://redis.io/download/然后解压 进入目录输入测试命令: sudomaketest没问题进行安装:sudomakeinstall安装成功redis-server启动redis服务redis-cli进行连接,接着按照key,value进行设置测试是否能正常set、get报错......