91视频免费?看_蜜芽MY188精品TV在线观看_国产免费无遮挡在线观看视频_深夜国产_亚洲精品欧洲精品_欧美黑人粗暴多交

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
成為第一個和作者交流的人吧
主站蜘蛛池模板: 阳朔县| 玉屏| 惠来县| 灵丘县| 蒙阴县| 浙江省| 白山市| 会理县| 柏乡县| 德保县| 合川市| 桃园县| 阿巴嘎旗| 涡阳县| 吴堡县| 如东县| 寿阳县| 宕昌县| 冕宁县| 岑溪市| 宣武区| 惠来县| 隆子县| 长兴县| 彭山县| 法库县| 北流市| 南乐县| 盐边县| 融水| 吉安市| 东阿县| 怀柔区| 水城县| 塔河县| 石棉县| 山阴县| 西宁市| 长海县| 句容市| 延吉市|