7 个不稳定版本
0.4.1 | 2023年11月9日 |
---|---|
0.4.0 | 2023年10月18日 |
0.3.1 | 2023年8月20日 |
0.3.0 | 2022年10月17日 |
0.1.1 | 2022年7月30日 |
#412 in 嵌入式开发
每月1,065次下载
在 4 个 crate 中使用 (via rbd_dimmer)
20KB
186 行
edge-executor
本 crate 提供了一个适用于微控制器和嵌入式系统的一般环境的最小异步执行器。
这是 smol 的 async-executor 的 no_std 一次性替换,其实现是 smol 的 async-task 的薄包装。
示例
// ESP-IDF example, local execution, local borrows.
// With STD enabled, you can also just use `edge_executor::block_on`
// instead of `esp_idf_svc::hal::task::block_on`.
use edge_executor::LocalExecutor;
use esp_idf_svc::hal::task::block_on;
fn main() {
let local_ex: LocalExecutor = Default::default();
// Borrowed by `&mut` inside the future spawned on the executor
let mut data = 3;
let data = &mut data;
let task = local_ex.spawn(async move {
*data += 1;
*data
});
let res = block_on(local_ex.run(async { task.await * 2 }));
assert_eq!(res, 8);
}
// STD example, work-stealing execution.
use async_channel::unbounded;
use easy_parallel::Parallel;
use edge_executor::{Executor, block_on};
fn main() {
let ex: Executor = Default::default();
let (signal, shutdown) = unbounded::<()>();
Parallel::new()
// Run four executor threads.
.each(0..4, |_| block_on(ex.run(shutdown.recv())))
// Run the main future on the current thread.
.finish(|| block_on(async {
println!("Hello world!");
drop(signal);
}));
}
// WASM example.
use log::{info, Level};
use edge_executor::LocalExecutor;
use static_cell::StaticCell;
use wasm_bindgen_futures::spawn_local;
use gloo_timers::future::TimeoutFuture;
static LOCAL_EX: StaticCell<LocalExecutor> = StaticCell::new();
fn main() {
console_log::init_with_level(Level::Info).unwrap();
// Local executor (futures can be `!Send`) yet `'static`
let local_ex = &*LOCAL_EX.init(Default::default());
local_ex
.spawn(async {
loop {
info!("Tick");
TimeoutFuture::new(1000).await;
}
})
.detach();
spawn_local(local_ex.run(core::future::pending::<()>()));
}
亮点
no_std
(但需要alloc
)- 执行器以受控的方式使用分配:仅在创建新任务时以及执行器本身构建期间;
- 对于
no_std
和 "no_alloc" 执行器,请参阅 embassy-executor,它静态预分配所有任务。
- 在无
core::sync::atomic
支持的目标上运行,多亏了 portable-atomic; - 不假设 RTOS,也可以完全裸机运行;
- 默认情况下,基于原子锁的、有界任务队列,适用于从 FreeRTOS 或 ESP-IDF 等ISR直接唤醒执行器,无界也是选项(具有
unbounded
功能,但这可能意味着 ISR 上下文中的潜在分配,应避免)。
从 async-executor 继承的优秀功能
- 堆借用:在执行器上生成的 future 只需要与执行器本身存在一样长的时间。没有
F: Future + 'static
约束; - 完全可移植和异步。
Executor::run
简单返回一个Future
。轮询此 future 将运行执行器,即block_on(executor.run(core::future:pending::<()>()))
; const new
构造函数。
注意:要在没有原子操作 core
的 Rust no_std
目标(例如 riscv32imc-unknown-none-elf
和类似的单核 MCU)上编译,请启用特性 portable-atomic
和 critical-section
。即:
cargo build --features portable-atomic,critical-section --no-default-features --target <your-target>
依赖项
~0.5-1MB
~16K SLoC