Rust异步编程工具block_on_proc的使用:高效阻塞过程宏与异步代码同步执行方案

Rust异步编程工具block_on_proc的使用:高效阻塞过程宏与异步代码同步执行方案

block_on 过程宏

block_on过程宏可以为impl块中的每个异步方法自动生成一个阻塞版本的方法。它支持tokioasync-std两种异步运行时,生成的阻塞方法会以_blocking作为后缀。

tokio示例

use block_on::block_on;

struct Tokio {}

#[block_on("tokio")]
impl Tokio {
    async fn test_async(&self) {}        
}

上面的代码会生成以下实现块:

async fn test_async(&self) {}
        
fn test_async_blocking(&self) {
    use tokio::runtime::Runtime;
    let mut rt = Runtime::new().unwrap();
    rt.block_on(self.test_async())
}

async-std示例

use block_on::block_on;

struct AsyncStd {}

#[block_on("async-std")]
impl AsyncStd {
    async fn test_async(&self) {}        
}

这会生成以下方法:

async fn test_async(&self) {}        

fn test_async_blocking(&self) {
      use async_std::task;
      task::block_on(self.test_async())
}

完整示例代码

// Cargo.toml依赖
// [dependencies]
// block_on_proc = "0.2.0"
// tokio = { version = "1.0", features = ["full"] }
// async-std = "1.12.0"

use block_on::block_on;

// 使用Tokio运行时的服务
struct TokioService {}

#[block_on("tokio")]
impl TokioService {
    async fn fetch_data(&self) -> String {
        // 模拟异步网络请求
        tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
        "Data from tokio async fetch".to_string()
    }
}

// 使用async-std运行时的服务
struct AsyncStdService {}

#[block_on("async-std")]
impl AsyncStdService {
    async fn compute_result(&self) -> i32 {
        // 模拟异步计算
        async_std::task::sleep(std::time::Duration::from_secs(1)).await;
        42
    }
}

fn main() {
    // 使用Tokio服务
    let tokio_service = TokioService {};
    
    // 同步调用tokio异步方法
    let data = tokio_service.fetch_data_blocking();
    println!("Tokio blocking call result: {}", data);
    
    // 使用Async-std服务
    let async_std_service = AsyncStdService {};
    
    // 同步调用async-std异步方法
    let result = async_std_service.compute_result_blocking();
    println!("Async-std blocking call result: {}", result);
}

这个完整示例展示了:

  1. 如何为两种不同的异步运行时(tokio和async-std)使用block_on_proc宏
  2. 如何定义异步方法
  3. 如何在同步上下文中通过生成的_blocking方法调用异步代码
  4. 实际运行效果演示

1 回复

Rust异步编程工具block_on_proc的使用:高效阻塞过程宏与异步代码同步执行方案

介绍

block_on_proc是一个Rust过程宏工具,用于在同步上下文中高效地执行异步代码。它解决了在过程宏中调用异步函数时的常见问题,提供了一种简洁的方式将异步代码同步化执行。

主要特点

  • 允许在同步过程宏中直接调用异步函数
  • 简化异步代码在同步上下文中的集成
  • 提供高效的事件循环管理
  • 保持代码简洁性和可读性

使用方法

基本使用

首先在Cargo.toml中添加依赖:

[dependencies]
block_on_proc = "0.1"
tokio = { version = "1.0", features = ["full"] }

然后在代码中使用:

use block_on_proc::block_on;

#[block_on]
async fn fetch_data() -> String {
    // 模拟异步操作
    tokio::time::sleep(std::time::Duration::from_secs(1)).await;
    "Hello from async!".to_string()
}

fn main() {
    let result = fetch_data();
    println!("{}", result); // 输出: "Hello from async!"
}

在过程宏中使用

use proc_macro::TokenStream;
use quote::quote;
use block_on_proc::block_on;

#[proc_macro]
pub fn make_async(input: TokenStream) -> TokenStream {
    // 在过程宏中调用异步函数
    let result = fetch_async_data().await;
    
    // 生成代码
    let expanded = quote! {
        fn generated_fn() -> &'static str {
            #result
        }
    };
    
    expanded.into()
}

#[block_on]
async fn fetch_async_data() -> String {
    tokio::time::sleep(std::time::Duration::from_secs(1)).await;
    "Async data processed".to_string()
}

错误处理

use block_on_proc::block_on;

#[block_on]
async fn might_fail() -> Result<String, String> {
    tokio::time::sleep(std::time::Duration::from_secs(1)).await;
    if rand::random() {
        Ok("Success!".to_string())
    } else {
        Err("Failed!".to_string())
    }
}

fn main() {
    match might_fail() {
        Ok(s) => println!("{}", s),
        Err(e) => eprintln!("Error: {}", e),
    }
}

注意事项

  1. block_on_proc会创建一个新的Tokio运行时来执行异步代码
  2. 在频繁调用的场景中,考虑性能影响
  3. 不适合在已经异步的上下文中使用
  4. 对于复杂的异步操作,建议使用专门的异步设计模式

高级用法

自定义运行时配置

use block_on_proc::block_on_with_runtime;
use tokio::runtime::Builder;

#[block_on_with_runtime(
    runtime = "Builder::new_multi_thread().enable_all().build().unwrap()"
)]
async fn custom_runtime_example() -> String {
    tokio::time::sleep(std::time::Duration::from_secs(1)).await;
    "Custom runtime".to_string()
}

与同步代码混合使用

use block_on_proc::block_on;

fn sync_function() -> String {
    "Sync ".to_string()
}

#[block_on]
async fn async_function(base: String) -> String {
    tokio::time::sleep(std::time::Duration::from_secs(1)).await;
    base + "Async"
}

fn main() {
    let sync_part = sync_function();
    let result = async_function(sync_part);
    println!("{}", result); // 输出: "Sync Async"
}

完整示例demo

下面是一个综合使用block_on_proc的完整示例,展示了从基本使用到错误处理的完整流程:

use block_on_proc::block_on;
use tokio::time;

// 基本异步函数
#[block_on]
async fn basic_async() -> String {
    time::sleep(time::Duration::from_secs(1)).await;
    "Basic async completed".to_string()
}

// 带错误处理的异步函数
#[block_on]
async fn async_with_error() -> Result<String, String> {
    time::sleep(time::Duration::from_secs(1)).await;
    if rand::random() {
        Ok("Operation succeeded".to_string())
    } else {
        Err("Operation failed".to_string())
    }
}

// 自定义运行时的异步函数
#[block_on_with_runtime(
    runtime = "tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap()"
)]
async fn custom_runtime_async() -> String {
    time::sleep(time::Duration::from_secs(1)).await;
    "Custom runtime async completed".to_string()
}

fn main() {
    // 基本使用示例
    let basic_result = basic_async();
    println!("{}", basic_result);
    
    // 错误处理示例
    match async_with_error() {
        Ok(s) => println!("Success: {}", s),
        Err(e) => eprintln!("Error: {}", e),
    }
    
    // 自定义运行时示例
    let custom_result = custom_runtime_async();
    println!("{}", custom_result);
    
    // 混合同步和异步代码示例
    let sync_data = "Sync data: ".to_string();
    #[block_on]
    async fn process_data(input: String) -> String {
        time::sleep(time::Duration::from_secs(1)).await;
        input + "processed asynchronously"
    }
    let mixed_result = process_data(sync_data);
    println!("{}", mixed_result);
}

block_on_proc为Rust开发者提供了一种在同步上下文中处理异步代码的便捷方式,特别适合需要在过程宏中集成异步功能的场景。

回到顶部