【问题标题】:How to reuse Tokio runtime in Rust FFI library如何在 Rust FFI 库中重用 Tokio 运行时
【发布时间】:2021-07-09 13:33:32
【问题描述】:

我想为 sn_api 库编写一个 FFI 包装器,其中包含 async 函数。它将用于用 Red 编写的单线程非异步代码。

found,最简单的方法是在每个导出的函数中使用Runtime::new().unwrap().block_on(...),尽管它涉及大量创建新的 Tokio 运行时并且似乎太重而无法在每次调用时运行:

use std::os::raw::c_char;
use std::ffi::{CString, CStr};
use sn_api::{BootstrapConfig, Safe};
use tokio::runtime::Runtime;

#[no_mangle]
pub extern "C" _safe_connect(ptr: *const Safe, bootstrap_contact: *const c_char) {
    assert!(!ptr.is_null());
    let _safe = unsafe {
        &*ptr
    };

    let bootstrap_contact = unsafe {
        CStr::from_ptr(bootstrap_contact)
    }

    let mut bootstrap_contacts = BootstrapConfig::default();
    bootstrap_contacts.insert(bootstrap_contact.parse().expect("Invalid bootstrap address"));

    // how to reuse the Runtime in other functions?
    Runtime::new().unwrap().block_on(_safe.connect(None, None, Some(bootstrap_contacts)));
}

是否可以在一个公共 Runtime 上运行所有异步函数?我想这需要创建一些单例/全局,但我的库是用crate-type = ["cdylib"] 编译的,这对于全局来说似乎不是一个好地方。最好的方法是什么?

【问题讨论】:

    标签: rust ffi rust-tokio


    【解决方案1】:

    我决定采用一种方法,在其中创建一个 Tokio Runtime,然后将其传递给每个包含异步代码的 FFI 函数调用:

    use std::os::raw::c_char;
    use std::ffi::{CString, CStr};
    use sn_api::{BootstrapConfig, Safe};
    use tokio::runtime::Runtime;
    
    #[no_mangle]
    pub extern "C" fn init_runtime() -> *mut Runtime {
        Box::into_raw(Box::new(Runtime::new().unwrap()))
    }
    
    #[no_mangle]
    pub extern "C" _safe_connect(rt_ptr: *mut Runtime, safe_ptr: *mut Safe, bootstrap_contact: *const c_char) {
        assert!(!safe_ptr.is_null());
        assert!(!rt_ptr.is_null());
    
        let bootstrap_contact = unsafe {
            CStr::from_ptr(bootstrap_contact)
        }
        let mut bootstrap_contacts = BootstrapConfig::default();
        bootstrap_contacts.insert(bootstrap_contact.parse().expect("Invalid bootstrap address"));
    
        unsafe {
            let _safe = &mut *safe_ptr;
            let rt = &mut *rt_ptr;
            rt.block_on(_safe.connect(None, None, Some(bootstrap_contacts))).unwrap();
        }
    }
    

    【讨论】:

    • runtime 实际上与 C-ABI 兼容吗?我猜 Box 对此有帮助……
    • 另外,请查看docs.rs/async-ffi/latest/async_ffi,我认为它可以帮助您从应用程序中获得更好的性能。
    【解决方案2】:

    试试这个。

    从这里:

    #[tokio::main]
    async fn main() {
        println!("hello");
    }
    

    转化为:

    fn main() {
        let mut rt = tokio::runtime::Runtime::new().unwrap();
        rt.block_on(async {
            println!("hello");
        })
    }
    

    参考:https://tokio.rs/tokio/tutorial/hello-tokio#async-main-function

    【讨论】:

    • 感谢您的帮助。虽然这并不能解决我的问题,因为我的代码是一个库,所以我没有main() 函数。另外,我不想在我的库的每个函数中都创建一个Runtime
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-21
    • 2017-12-31
    • 1970-01-01
    • 1970-01-01
    • 2022-06-19
    相关资源
    最近更新 更多