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");
}

这个示例展示了:

  1. 使用#[pollster::main]属性标记异步main函数
  2. 在main函数中await一个异步任务
  3. 使用block_on()方法同步执行future
  4. 使用#[pollster::test]进行异步测试
  5. 处理不同类型的异步操作
  6. 在测试中组合使用await和block_on

1 回复

以下是关于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();
    }
}

注意事项:

  1. 这个示例中文件读取实际上是同步操作,只是通过async/await语法包装
  2. 在生产环境中处理真正的异步IO时,应该使用tokio或async-std等运行时
  3. pollster适用于简单的异步操作执行和测试场景
回到顶部