99久久全国免费观看_国产一区二区三区四区五区VM_久久www人成免费看片中文_国产高清在线a视频大全_深夜福利www_日韩一级成人av

Rust 異步 —— 讓嵌入式編程更加簡單

FuturesRust中用于異步編程,類似JavaScriptpromise的原理,兩者都是async/await語句的基礎,用戶可用它們用串行編程的方式實現異步的功能。

Futures在標準的std和嵌入式的nostd環境都有支持,使用方式一致,在std環境中,比較出名的有Tokio實現了異步的平臺,在嵌入式領域中,embassy也提供了高效的異步平臺。

到底什么是 Future

簡單的說,Future用于表示一些異步計算的值,也就是說無法在當前得出最終的結果,但由于串行的程序中,又需要該計算的結果用于后續的操作。舉個例子,在嵌入式中,通常處理串口接收和處理數據時,采用串行編程的方式如下:

void loop() {
    char ch;
    if (ch == serial.read())
        switch ch {
            case 'A': do_someting(); break;
            case 'B':   do_someting_else(); break;
            ...

            default: break;
        }
    }
    do_someting();
}

在這個簡單的例程中,可以很容易看出處理的邏輯,但是CPU的執行效率卻很低,CPU或進程會阻塞在串口的讀接口中。也許更加有經驗的程序員會用中斷或操作系統來實現這個功能。但是需要加倍小心多線程或中斷引發的其他風險,同時代碼的可閱讀性會降低,需要去了解操作系統和信號量等全局變量。如果使用RustFuture來替代該程序,則可簡單如下:

async fn loop() {
    let ch = serial.read().await;
    match ch {
        'A' => {
            do_someting();
        }
        'B' => {
            do_someting_else(); 
        }
        _ => {
            do_some();
        }
    }
    do_someting();
}

在異步的Rust代碼中,同樣保持了串行的編程模式,但CPU或線程不會在read()停留等待可讀數據,而是在后臺數據來臨時自動喚醒。這樣提高了運行效率。

Future的實現原理

在大多數需要等待結束的任務中,系統后臺需要一個執行器,通過喚醒Future的事件來重新激活await語句,簡單得說,需要執行器對該任務實現任務和激活機制的抽象,該抽象無需反復去查詢事件信號,而任務是被動讓激活信號重新喚醒。Future的簡單模型如下:

se std::cell::RefCell;

thread_local!(static NOTIFY: RefCell = RefCell::new(true));

struct Context<'a> {
    waker: &'a Waker,
}

impl<'a> Context<'a> {
    fn from_waker(waker: &'a Waker) -> Self {
        Context { waker }
    }

    fn waker(&self) -> &'a Waker {
        &self.waker
    }
}

struct Waker;

impl Waker {
    fn wake(&self) {
        NOTIFY.with(|f| *f.borrow_mut() = true)
    }
}

enum Poll {
    Ready(T),
    Pending,
}

trait Future {
    type Output;

    fn poll(&mut self, cx: &Context) -> Poll;
}

#[derive(Default)]
struct MyFuture {
    count: u32,
}

impl Future for MyFuture {
    type Output = i32;

    fn poll(&mut self, ctx: &Context) -> Poll {
        match self.count {
            3 => Poll::Ready(3),
            _ => {
                self.count += 1;
                ctx.waker().wake();
                Poll::Pending
            }
        }
    }
}

fn run(mut f: F) -> F::Output
where
    F: Future,
{
    NOTIFY.with(|n| loop {
        if *n.borrow() {
            *n.borrow_mut() = false;
            let ctx = Context::from_waker(&Waker);
            if let Poll::Ready(val) = f.poll(&ctx) {
                return val;
            }
        }
    })
}

fn main() {
    let my_future = MyFuture::default();
    /// 將輸出:Output: 3
    println!("Output: {}", run(my_future));
}

如上所示,run函數帶有一個Future屬性,可理解為調度器。在NOTIFY的信號中重新激活任務,然后返回執行結果,給Poll::Ready帶出。通常NOTIFYloop閉包至少會執行一次,第一次是首次進入poll任務,如果poll任務后沒有結束,將會在Waker信號被激活時重新喚起執行poll的任務。如果沒有喚醒事件,則調度器不會主動去執行PollContext用來傳遞任務的上下文,可用來保存當前任務的事件信號等。Poll則是一個簡單的枚舉,Ready代表任務可以結束后的結果,將帶回結果返回值,Pending則代表當前任務并未結束,則繼續睡眠。Futuretrait 則是任務的抽象,任何只要實現Future``trait,都可使用在異步編程中,即使用async/awit。在該例中根據原理實現了一個最簡單的Future的調度器,以及一個實現了Future的結構體對象MyFuture。也許看起來要實現異步需要這么多代碼,似乎有點復雜!別擔心,這些Rust都已經為您提供了,你需要寫的也就是main函數的內容,甚至更加簡單。下面展示embassy使用異步的方式處理串口數據。

#[embassy_executor::main]
async fn main(_spawner: Spawner) {
    let p = embassy_nrf::init(Default::default());
    let mut config = uarte::Config::default();
    config.parity = uarte::Parity::EXCLUDED;
    config.baudrate = uarte::Baudrate::BAUD115200;

    let mut uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config);

    info!("uarte initialized!");

    // Message must be in SRAM
    let mut buf = [0; 8];
    buf.copy_from_slice(b"Hello!\r\n");

    unwrap!(uart.write(&buf).await);
    info!("wrote hello in uart!");

    loop {
        info!("reading...");
        unwrap!(uart.read(&mut buf).await);
        info!("writing...");
        unwrap!(uart.write(&buf).await);
    }
}

最后

Rust中使用Future是零成本抽象的,即不會生成多余的狀態邏輯代碼,同時CPU的運行也不會造成負荷,同時代碼的可閱讀性依舊很強。如果有興趣可以深入閱讀以下書籍:

  • Asynchronous Programming in Rust:https://rust-lang.github.io/async-book/02_execution/02_future.html
  • Async programming in Rust with async-std:https://book.async.rs/concepts/futures
  • Async Rust:https://www.oreilly.com/library/view/async-rust/9781098149086/
聲明:本內容為作者獨立觀點,不代表電子星球立場。未經允許不得轉載。授權事宜與稿件投訴,請聯系:editor@netbroad.com
覺得內容不錯的朋友,別忘了一鍵三連哦!
贊 2
收藏 3
關注 14
成為作者 賺取收益
全部留言
0/200
成為第一個和作者交流的人吧
主站蜘蛛池模板: 一本久久综合亚洲鲁鲁五月天 | 亚洲人成网在线播放 | 亚洲无码手机在线观看视频 | www.综合久久| 国产香蕉伊蕉伊中文在线视频 | 成人免费xxx在线观看 | 91无码视频在线观看 | 久久不见久久见www免费视频 | 亚洲欧美闷骚少妇影院 | 国产精品专区第一区 | 亚洲国产精品一区二区久久亚洲午夜 | 中文在线综合 | 91综合网人人 | 开心婷婷中文字幕 | 一区二区三区日韩在线观看 | 亚洲成av人不卡无码影片 | 亚洲黄色特级片 | 欧美激情视频一区二区 | 人妻丰满熟妇AV无码区乱 | 色综合色天天久久婷婷基地 | 久久国产午夜精品理论片推荐 | 在线天堂一区 | 欧美一区a | 久久久99精品免费观看乱色 | 91精品国产综合久久久亚洲 | 日本69视频 | 亚洲视频一区国产 | 亚洲精品一区二区三区中文字幕 | 91精品国产乱码久久久软件 | 麻豆一区二区大豆行情 | 国产精品第100页 | 日韩一区二区精品葵司在线 | 国产二级一片内射视频播放 | 欧美视频亚洲视频 | 综合亚洲自拍 | 欧美一区二区三区在线看 | 亚洲欧美综合国产不卡 | 成年人免费在线看网站 | 人人妻人人澡人人爽欧美一区 | 三年片免费观看影视大全满天星 | 美女扒开腿让男人桶爽网站 |