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
成為第一個和作者交流的人吧
主站蜘蛛池模板: 少妇又色又爽又高潮 | 日本在线播放一二三区 | 亚洲日韩av片在线观看 | 人妻人人澡人人添人人爽 | 人人干干人人 | 久久中文字幕一区二区三区 | 亚洲综合色丁香婷婷六月图片 | 九一欧美 | 精品人妻无码一区二区三区丝袜 | 亚洲第一无码xxxxxx | 色影天堂 | 麻豆视频免费在线观看 | 天堂在线www资源在线 | 亚洲综合色婷婷六月丁香宅男大增 | 99精品在线播放 | 欧美巨大另类极品videosbest | 天天爱天天做天天添天天欢 | 麻豆传媒视频在线播放 | 国产亚洲综合精品 | 亚洲国产天堂久久综合网 | 久久AV无码乱码A片无码 | 放荡老师张开双腿任我玩 | 亚洲精品中文字幕无码av | 91人人精品| 在线播放毛片 | 与丰满少妇做爽视频 | 亚洲成色www久久网站 | 亚洲AV网址在线 | 96超碰在线 | 欧美日韩激情在线 | 久久亚洲AⅤ精品网站 | 性色aⅤ极品无码专区亚洲 成人水多啪啪片 | 无码AV免费一区二区三区四区 | 青青草视频在线观 | 高中生高潮抽搐喷出白浆视频 | 九色蝌蚪自拍 | 欧美性猛交xxxx乱大交免费看 | 日韩欧美毛片免费观看 | 337p日本欧洲亚洲 | 92精品国产自产在线观看481页 | 免费成人在线观看 |