< 返回版块

eweca-d 发表于 2021-03-26 20:16

需要加载某个动态库(106kb,C++编写,提供C接口),我发现使用推荐的方法

// loop for 2000
fn call_dynamic(x: Vec<i32>) -> Result<u32, Box<dyn std::error::Error>> {
    unsafe {
        let lib = libloading::Library::new("/path/to/liblibrary.so")?;
        let func: libloading::Symbol<unsafe fn(*const i32) -> u32> = lib.get(b"my_func")?;
        Ok(func(x.as_ptr()))
    }
}

时,每次调用的时间高达1ms多,其中主要由libloading::Library::new这个载入动态库的行为占了绝大部分的时间消耗。这个对于我来说是不可容忍的,因为我需要调用这个函数2000次,程序总消耗在6.2s左右,这个函数就占用了接近3秒的时间。也就是有有一半的时间拿来载入动态库了,太浪费时间了。

我唯一想到的办法是:

fn calculator() {
        let lib;
        let func;
        unsafe {
        lib = libloading::Library::new("/path/to/liblibrary.so").unwrap();
        func: libloading::Symbol<unsafe fn(*const i32) -> u32> = lib.get(b"my_func").unwrap();
        }
        let ret = call_dynamic(vec![0, 1, 2], func); // loop for 2000
}

fn call_dynamic(x: Vec<i32>, func: Symbol<unsafe fn(*const i32) -> u32>) -> u32 {
    unsafe {
        func(x.as_ptr())
    }
}

但是这个实现我觉得也太丑了吧。而且如上所示,这是一个库,没有入口,假如我需要calculator2()函数,我又要重复导入。

有没有办法把这个设置成全局变量,然后无论哪个函数,都可以很方便的调用func啊,类似

// error: calls in constants are limited to constant functions, tuple structs and tuple variants
const lib = Library::new("spsolver.dll").unwrap();
const func = lib.get(b"spsolver_LU").unwrap();
fn call_dynamic(x: Vec<i32>) -> u32 {
    unsafe {
        func(x.as_ptr())
    }
}

显然这个不行,因为Library::new的签名是pub unsafe fn new<P: AsRef<OsStr>>(filename: P) -> Result<Library, Error>。真的很无语。

求教!有没有办法能像使用自己写的rust函数一样,编译时一次载入动态库,然后处处使用?

评论区

写评论
jmjoy 2021-03-29 18:22

😅

作者 eweca-d 2021-03-26 21:54

牛啊大佬!一把成功。程序运行时间3.2S左右,与我手写的丑陋的一次载入运行速度完全一致!

万分感谢!!!

--
👇
ywxt:

use std::{os::raw::c_int, time::Instant};

use libloading::{Library, Symbol};
use once_cell::sync::OnceCell;

fn get_func() -> &'static Symbol<'static, unsafe fn(c_int) -> c_int> {
    static LIBRARY: OnceCell<Library> = OnceCell::new();
    static FUNC: OnceCell<Symbol<'static, unsafe fn(c_int) -> c_int>> = OnceCell::new();
    let library = LIBRARY.get_or_init(|| unsafe { Library::new("test.dll").unwrap() });
    FUNC.get_or_init(|| unsafe { library.get(b"test").unwrap() })
}

fn main() {
    let now = Instant::now();
    for _ in 0..2000 {
        let func = get_func();
        unsafe {
            println!("{}", func(1));
        }
    }
    let elapsed = now.elapsed();
    println!("{:.6?}",elapsed);
    
}
364.853200ms
ywxt 2021-03-26 21:34
use std::{os::raw::c_int, time::Instant};

use libloading::{Library, Symbol};
use once_cell::sync::OnceCell;

fn get_func() -> &'static Symbol<'static, unsafe fn(c_int) -> c_int> {
    static LIBRARY: OnceCell<Library> = OnceCell::new();
    static FUNC: OnceCell<Symbol<'static, unsafe fn(c_int) -> c_int>> = OnceCell::new();
    let library = LIBRARY.get_or_init(|| unsafe { Library::new("test.dll").unwrap() });
    FUNC.get_or_init(|| unsafe { library.get(b"test").unwrap() })
}

fn main() {
    let now = Instant::now();
    for _ in 0..2000 {
        let func = get_func();
        unsafe {
            println!("{}", func(1));
        }
    }
    let elapsed = now.elapsed();
    println!("{:.6?}",elapsed);
    
}
364.853200ms
1 共 3 条评论, 1 页