Rust同步异步代码桥接问题:EnterError报错求助
Rust同步异步桥接问题:同步回调内执行异步代码触发EnterError
问题场景
我需要处理Rust中同步与异步代码的桥接需求:某异步库仅支持注册同步回调,但我必须在该回调内执行异步逻辑。具体来说,我使用tokio-openssl crate处理TLS连接,配置SslContext时,OpenSSL仅允许在收到ClientHello等事件时注册同步回调,而我需要在回调中运行异步代码。
我尝试通过futures::executor::block_on(async { ... })和tokio::task::spawn_blocking()组合实现,但触发了如下报错:
thread panicked at 'cannot execute
LocalPoolexecutor from within another executor: EnterError
最小复现代码
以下是能复现问题的最小示例:
use std::time::Duration; // 签名无法修改,由第三方库控制 fn user_fn() { // 阻塞10ms futures::executor::block_on(async { tokio::time::sleep(Duration::from_millis(10)).await; }); } // 函数无法修改,由第三方库控制 async fn library(callback: impl Fn()) { // 阻塞10ms callback(); } #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { // 直接调用library(user_fn).await会阻塞runtime 10ms,影响异步调度 // 所以我尝试把阻塞任务放到允许阻塞的线程中执行... tokio::task::spawn_blocking(|| futures::executor::block_on(library(user_fn))).await?; // 运行后崩溃,报错: // thread 'tokio-runtime-worker' panicked at 'cannot execute `LocalPool` executor from within another executor: EnterError println!("Finished"); Ok(()) }
贴近实际场景的详细示例
下面是更贴近真实OpenSSL回调场景的代码,展示库的接口限制:
use std::time::Duration; // 模拟OpenSSL的SslContext配置,仅支持同步回调 struct SslContext { client_hello_callback: Option<fn()>, } impl SslContext { fn new() -> Self { SslContext { client_hello_callback: None } } // 注册ClientHello同步回调,签名由库定义无法修改 fn set_client_hello_callback(&mut self, callback: fn()) { self.client_hello_callback = Some(callback); } // 模拟TLS握手触发回调,异步方法 async fn accept(&self) { println!("Starting TLS handshake..."); if let Some(callback) = &self.client_hello_callback { callback(); // 调用同步回调 } println!("Handshake completed"); } } // 我需要在回调中执行的异步逻辑 async fn async_operation() { println!("Executing async operation..."); tokio::time::sleep(Duration::from_millis(10)).await; println!("Async operation done"); } // 我的同步回调,需要调用异步逻辑 fn client_hello_callback() { // 尝试用block_on执行异步代码,触发问题 futures::executor::block_on(async_operation()); } #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { let mut ctx = SslContext::new(); ctx.set_client_hello_callback(client_hello_callback); // 直接调用会阻塞runtime // ctx.accept().await; // 尝试用spawn_blocking包装,仍然报错 tokio::task::spawn_blocking(|| futures::executor::block_on(ctx.accept())).await?; println!("Finished"); Ok(()) }
内容的提问来源于stack exchange,提问作者linuskmr
相关产品推荐
相关产品推荐

