从两个完全不同的地方调用一个函数,我只想在线程安全环境中运行该函数一次。考虑这种情况:
use std::sync::{Once, Mutex};
use lazy_static::lazy_static;
lazy_static! {
static ref INIT: Once = Once::new();
static ref VALUE: Mutex<Option<bool>> = Mutex::new(None);
}
fn expensive_function() -> bool {
println!("Expensive computation happening...");
false
}
fn get_value() -> bool {
INIT.call_once(|| {
*VALUE.lock().unwrap() = Some(expensive_function());
});
VALUE.lock().unwrap().unwrap()
}
fn main() {
// First call - will run expensive_function
println!("First call: {}", get_value());
// Second call - will return cached value
println!("Second call: {}", get_value());
}
这可以工作并提供预期的输出,并且使用互斥体来处理线程环境。
Expensive computation happening... First call: false Second call: false
但是,有些情况我无法思考,需要专家的帮助。 1. 如果线程处于 Poisned 状态怎么办? 2. 我相信这么多 unwraps() 都不好。
社区有什么建议?第二次调用也可能在其他文件中。
我曾尝试明确处理中毒线程,但无法使其工作。还尝试使用匹配语句以避免打开并感到困惑。
std::sync::LazyLock
可以让你摆脱 Option
和 Mutex
,消除两个展开:
static VALUE: LazyLock<bool> = LazyLock::new(|| expensive_function());
fn get_value() -> bool {
*VALUE
}
如果您确实需要偶尔修改数据,那么由于中毒,您仍然需要
Mutex
及其解包。这种展开是您学习接受的一种模式 - 毕竟,如果互斥锁确实中毒了(持有它的线程陷入恐慌),那么您可能“想要”将恐慌传播到尝试使用它的线程。而如果你还是觉得互斥相关的unwrap()
难以接受,你可以从std::sync::Mutex
切换到parking_lot::Mutex
,后者不具备中毒功能。