Rust异步运行时宏pollster-macro的使用:简化异步代码编写与Future执行
Rust异步运行时宏pollster-macro的使用:简化异步代码编写与Future执行
Pollster介绍
Pollster是一个极其简洁的Rust异步执行器,它允许你阻塞线程直到一个future完成。
use pollster::FutureExt as _;
let my_fut = async {};
let result = my_fut.block_on();
这就是它的全部功能。不需要引入大量crate来评估一个future。
为什么这很有用?
随着async函数的稳定,Rust生态系统中越来越多的库暴露async API。这对于构建高度并发的Web应用程序很有帮助。
然而,很多人并没有构建高度并发的Web应用程序,但却遇到无法从同步代码轻松调用的async函数。pollster就是为解决这种情况而生的:它允许你原地评估future而不需要启动像tokio或async_std这样重量级的运行时。
极简主义
Pollster秉承UNIX哲学的理念:做一件事,并把它做好。它没有依赖项,编译速度快,并且仅由约100行经过良好审计的代码组成。
行为
Pollster会同步阻塞线程直到future完成。它不会自旋,而是将线程置于等待状态直到future被轮询完成。
兼容性
pollster不能用于所有的futures,因为有些需要特定的运行时或反应器。如果你已经引入了创建此类future所需的依赖项,那么你的依赖树中可能已经有了一个设计用于轮询你的future的block_on版本,可以直接使用那个。
宏
当使用macro crate特性时,可以使用属性宏来标记async fn main():
#[pollster::main]
async fn main() {
let my_fut = async {};
my_fut.await;
}
如果用不同的名称重新导出了这个crate而不是pollster,必须指定它:
#[pollster::main(crate = renamed_pollster)]
async fn main() {
let my_fut = async {};
my_fut.await;
}
也可以使用#[pollster::test]
进行测试。
与futures::executor::block_on的比较
pollster与futures crate中的block_on函数做大致相同的事情。如果你的依赖树中已经有了futures,可以直接使用它。pollster主要用于那些不想为了评估简单futures而将futures或另一个运行时如tokio引入其依赖树的应用程序。
完整示例代码
// Cargo.toml中添加依赖
// pollster = "0.3"
// pollster-macro = "0.3"
use std::time::Duration;
// 异步函数示例
async fn fetch_data() -> String {
// 模拟异步操作
tokio::time::sleep(Duration::from_secs(1)).await;
"Data fetched".to_string()
}
// 使用pollster宏标记异步main函数
#[pollster::main]
async fn main() {
// 正常await异步函数
let data = fetch_data().await;
println!("{}", data); // 输出: "Data fetched"
// 使用block_on同步执行future
let result = async {
tokio::time::sleep(Duration::from_millis(500)).await;
42
}.block_on();
println!("Result: {}", result); // 输出: "Result: 42"
}
// 异步测试示例
#[pollster::test]
async fn test_async_function() {
let value = async {
tokio::time::sleep(Duration::from_millis(100)).await;
"test value"
}.await;
assert_eq!(value, "test value");
}
// 另一个示例展示不同类型的future
async fn compute_sum(a: i32, b: i32) -> i32 {
// 模拟计算延迟
tokio::task::yield_now().await;
a + b
}
#[pollster::test]
async fn test_computation() {
let sum = compute_sum(2, 2).await;
assert_eq!(sum, 4);
// 立即执行的future
let fast_result = async { "immediate" }.block_on();
assert_eq!(fast_result, "immediate");
}
这个示例展示了:
- 使用
#[pollster::main]
属性标记异步main函数 - 在main函数中await一个异步任务
- 使用
block_on()
方法同步执行future - 使用
#[pollster::test]
进行异步测试 - 处理不同类型的异步操作
- 在测试中组合使用await和block_on
以下是关于pollster-macro的完整示例演示,首先展示内容中提供的示例,然后给出一个综合示例:
内容中提供的示例
基本使用方法
// 使用block_on宏
use pollster::block_on;
fn main() {
let result = block_on(async {
// 异步代码块
42
});
println!("Result: {}", result); // 输出: Result: 42
}
// 使用Future扩展方法
use pollster::FutureExt;
fn main() {
let future = async { 42 };
let result = future.block_on();
println!("Result: {}", result); // 输出: Result: 42
}
高级用法
// 处理嵌套Future
use pollster::block_on;
async fn async_func() -> i32 {
42
}
async fn outer_async_func() -> i32 {
let inner = async_func().await;
inner * 2
}
fn main() {
let result = block_on(outer_async_func());
println!("Result: {}", result); // 输出: Result: 84
}
// 与标准库Future结合使用
use std::future::Future;
use pollster::block_on;
fn create_future() -> impl Future<Output = String> {
async {
"Hello, pollster!".to_string()
}
}
fn main() {
let greeting = block_on(create_future());
println!("{}", greeting); // 输出: Hello, pollster!
}
测试示例
#[cfg(test)]
mod tests {
use pollster::block_on;
#[test]
fn test_async_code() {
let result = block_on(async {
// 测试异步代码
42
});
assert_eq!(result, 42);
}
}
综合示例演示
下面是一个结合文件读取的完整示例,展示pollster在实际简单场景中的使用:
use pollster::block_on;
use std::fs;
// 异步读取文件内容
async fn read_file_async(path: &str) -> String {
// 注意:这不是真正的异步IO,只是演示
fs::read_to_string(path).unwrap()
}
// 处理文件内容的异步函数
async fn process_file(path: &str) -> (String, usize) {
let content = read_file_async(path).await;
let word_count = content.split_whitespace().count();
(content, word_count)
}
fn main() {
// 使用pollster执行异步操作
let (content, count) = block_on(process_file("example.txt"));
println!("文件内容: {}", content);
println!("单词数量: {}", count);
// 使用Future扩展方法
let future = async {
let (_, count) = process_file("example.txt").await;
count
};
let word_count = future.block_on();
println!("再次统计单词数: {}", word_count);
}
#[cfg(test)]
mod tests {
use super::*;
use pollster::block_on;
#[test]
fn test_file_processing() {
let test_content = "This is a test string";
fs::write("test.txt", test_content).unwrap();
let (content, count) = block_on(process_file("test.txt"));
assert_eq!(content, test_content);
assert_eq!(count, 5);
fs::remove_file("test.txt").unwrap();
}
}
注意事项:
- 这个示例中文件读取实际上是同步操作,只是通过async/await语法包装
- 在生产环境中处理真正的异步IO时,应该使用tokio或async-std等运行时
- pollster适用于简单的异步操作执行和测试场景