仅调用一次具有返回类型的函数

问题描述 投票:0回答:1

从两个完全不同的地方调用一个函数,我只想在线程安全环境中运行该函数一次。考虑这种情况:

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() 都不好。

社区有什么建议?第二次调用也可能在其他文件中。

我曾尝试明确处理中毒线程,但无法使其工作。还尝试使用匹配语句以避免打开并感到困惑。

rust
1个回答
0
投票

正如评论中提到的,使用

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
,后者不具备中毒功能。

© www.soinside.com 2019 - 2024. All rights reserved.