2个版本
0.1.1 | 2023年1月26日 |
---|---|
0.1.0 | 2023年1月26日 |
#1105 in 异步
18KB
195 行
最坏执行器
可能的最简单异步执行器。
这个crate提供了一个名为 block_on
的单一函数,它接受一个future并在future解决之前阻塞当前线程。
它的工作方式是通过“自旋循环”遍历 poll
方法,直到它准备好。
好事是它可以非常有效地优化,例如 worst_executor::block_on(async { 42 })
编译为单个 mov
指令。
不好的一面是它实际上并不进行任何调度,这意味着如果你等待一个永远不会解决的future,你的程序将会挂起。这也是你可能不希望使用它的原因。
请注意,由于其简单性,该库仅使用 core
,不需要 std
或 alloc
,也没有任何依赖,实际上只有16行代码。
用法
将此添加到你的 Cargo.toml
[dependencies]
worst-executor = "0.1"
然后在你的 main.rs 中
fn main() {
worst_executor::block_on(async {
// Your async code goes here.
});
}
用例
比如说,你正在使用一个返回future的库,但你知道它不进行I/O,你希望在不引入完整的异步运行时(如tokio/smol/async-std)的情况下,在同步上下文中使用它。
你可以使用 worst_executor::block_on
来阻塞当前线程,直到future解决。
另一个场景可能是你希望在单个线程中运行“事件循环”,使用 async
rust。因此,你可以使用 core::future::join
宏与 futures::select
宏一起处理程序的控制流,同时在单个线程上运行且永不释放。
单线程tcp服务器
use async_net::{TcpListener, TcpStream};
use futures::{stream::FuturesUnordered, AsyncReadExt, AsyncWriteExt, StreamExt};
use worst_executor::block_on;
block_on(async {
let listener = TcpListener::bind("127.0.0.1:8080").await.unwrap();
let mut connection_handlers = FuturesUnordered::new();
// This stream is infinite so it's OK to call fuse.
let mut listener = listener.incoming().fuse();
loop {
futures::select! {
new_connection = listener.select_next_some() => connection_handlers.push(handle_connection(new_connection?)),
socket = connection_handlers.select_next_some() =>
if let Some(socket) = socket {
connection_handlers.push(handle_connection(socket));
},
}
}
})
async fn handle_connection(mut stream: TcpStream) -> Option<TcpStream> {
let mut buf = [0u8; 1024];
let n = match stream.read(&mut buf).await {
Ok(n) if n == 0 => return Some(stream),
Ok(n) => n,
Err(e) => {
eprintln!("failed to read from the socket {e:?}");
return None;
}
};
// Write the data back
stream.write_all(&buf[0..n]).await
.map_err(|e| eprintln!("failed to write to the socket {e:?}"))
.map(|()| stream)
.ok()
}