首页 > 其他分享 >OnceCell和OnceLock的介绍

OnceCell和OnceLock的介绍

时间:2023-06-13 20:56:33浏览次数:100  
标签:初始化 OnceLock 多线程 get 介绍 OnceCell data

OnceCell 和 OnceLock 都是 Rust 标准库中用于实现懒加载的数据结构,它们能够确保一个变量只被初始化一次。

OnceCell 是用于单线程环境下的懒加载数据结构。它可以用来存储某个值,并在需要时进行初始化,但是只能在单线程环境下使用。在多线程环境下,使用 OnceCell 会导致数据竞争问题,因此不适用于多线程环境。如果需要在多线程环境下使用懒加载数据结构,可以使用 std::sync::Once 或其他线程安全的数据结构。

OnceLock 是一个实验性类型,目前处于 unstable 状态,用于实现懒加载、并发安全的数据结构。和 std::sync::Once 类似,OnceLock 可以确保一个变量只被初始化一次,但是它可以在多线程环境下进行安全访问。需要注意的是,在使用 OnceLock 的时候需要将变量声明为静态变量。

两种新类型已稳定用于共享数据的一次性初始化, OnceCell 及其线程安全对应的 OnceLock 。 这些可以用于不需要立即构建的任何地方,甚至可能像全局变量中的非 const 数据一样不可能。

OnceLock的介绍

OnceLock 是一个用于实现懒加载、并发安全的数据结构,它是 Rust 标准库中的一个实验性类型,目前处于 unstable 状态。和 std::sync::Once 类似,OnceLock 可以确保一个变量只被初始化一次,但是它可以在多线程环境下进行安全访问。

以下是一个使用 OnceLock 的示例:

use std::sync::OnceLock;

static WINNER: OnceLock<&str> = OnceLock::new();

let winner = std::thread::scope(|s| {
    s.spawn(|| WINNER.set("thread"));

    std::thread::yield_now(); // give them a chance...

    WINNER.get_or_init(|| "main")
});

println!("{winner:?} wins!");

在这个例子中,我们使用 OnceLock 来创建一个名为 WINNER 的变量,并在多线程环境下使用它。我们使用 WINNER.set() 方法来设置 WINNER 变量的值,在另一个线程中,我们使用 WINNER.get_or_init() 方法来获取 WINNER 变量的值。get_or_init() 方法接受一个闭包作为参数,该闭包用于初始化变量的值,只有在变量未被初始化时才会执行。

需要注意的是,在使用 OnceLock 的时候需要将变量声明为静态变量。在多线程环境下,多个线程可以同时访问静态变量,因此需要使用 OnceLock 来确保变量只被初始化一次。

总之,OnceLock 是一个用于实现懒加载、并发安全的数据结构,它可以确保一个变量只被初始化一次,并且可以在多线程环境下进行安全访问。需要注意的是,OnceLock 目前处于实验性状态,可能会在未来的版本中发生改变。

OnceCell的介绍

OnceCell 是 Rust 标准库中的一个单线程版本的懒加载数据结构,用于储存某个值,并在需要时进行初始化。以下是对 OnceCell 的介绍和示例:

OnceCell 是一个单元格(cell)类型,它可以存储任意类型的值,但只能被初始化一次。一旦被初始化,它将一直存储该值,直到程序结束。OnceCell 可以用于那些需要在运行时才能确定值的场景,例如在单元测试中使用全局变量或在多线程环境下使用共享变量。

OnceCell 的初始化是通过调用其 get_or_init 方法来完成的,该方法接受一个闭包作为参数,该闭包在第一次调用时将被调用,返回值将被存储在 OnceCell 中。在后续调用 get_or_init 方法时,闭包不会被再次执行,而是返回已经初始化过的值。

以下是一个简单的例子,演示如何使用 OnceCell 来实现懒加载:

use std::cell::OnceCell;

let cell = OnceCell::new();
assert!(cell.get().is_none());

let value: &String = cell.get_or_init(|| "Hello, World!".to_string());
assert_eq!(value, "Hello, World!");
assert!(cell.get().is_some());

OnceCell 是用于单线程环境下的懒加载数据结构,因此它在多线程环境下是不安全的,会导致数据竞争问题。下面是一个使用方法错误的例子。

// use std::cell::OnceCell;

// static CACHE: OnceCell<Vec<i32>> = OnceCell::new();

// fn get_data() -> &'static Vec<i32> {
//     CACHE.get_or_init(|| {
//         let data = vec![1, 2, 3, 4, 5];
//         println!("Initializing cache");
//         data
//     })
// }

// let data = get_data();
// println!("Data: {:?}", data);

// let data = get_data();
// println!("Data: {:?}", data);

// error[E0277]: `OnceCell<Vec<i32>>` cannot be shared between threads safely
//   --> oncecell-and-oncelock-example/src/lib.rs:63:19
//    |
// 63 |     static CACHE: OnceCell<Vec<i32>> = OnceCell::new();
//    |                   ^^^^^^^^^^^^^^^^^^ `OnceCell<Vec<i32>>` cannot be shared between threads safely
//    |
//    = help: the trait `Sync` is not implemented for `OnceCell<Vec<i32>>`
//    = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::OnceLock` instead
//    = note: shared static variables must have a type that implements `Sync`

// For more information about this error, try `rustc --explain E0277`.
// warning: `oncecell-and-oncelock-example` (lib test) generated 4 warnings
// error: could not compile `oncecell-and-oncelock-example` (lib test) due to previous error; 4 warnings emitted

OnceCell 是用于单线程环境下的懒加载数据结构,因此它在多线程环境下是不安全的,会导致数据竞争问题。 如果需要在多线程环境下使用懒加载数据结构,可以使用 std::sync::Once 或其他线程安全的数据结构。

以下是使用 std::sync::Once 的示例,它可以在多线程环境下安全地初始化一次变量:

use std::sync::{Once, ONCE_INIT};

static mut CACHE: Option<Vec<i32>> = None;
static ONCE: Once = ONCE_INIT;

fn get_data() -> &'static Vec<i32> {
    unsafe {
        ONCE.call_once(|| {
            let data = vec![1, 2, 3, 4, 5];
            CACHE = Some(data);
            println!("Initializing cache");
        });

        CACHE.as_ref().unwrap()
    }
}

let data = get_data();
println!("Data: {:?}", data);

let data = get_data();
println!("Data: {:?}", data);

标签:初始化,OnceLock,多线程,get,介绍,OnceCell,data
From: https://www.cnblogs.com/Davirain/p/17478698.html

相关文章

  • 什么是双亲委派机制?介绍一些运作过程,双亲委派模型的好处;
    如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载......
  • Rdma-core介绍及编译
    一、RDMAlib库安装1.1介绍广义的VerbsAPI主要由两大部分组成verbs和rdma_cmVerbsAPI操作RDMA的函数接口,也就是说业界的RDMA应用,要么直接基于这组API编写,要么基于在VerbsAPI上又封装了一层接口的各种中间件编写。(rdma_cm)VerbsAPI向用户提供了有关RDMA的一切功能,典型的包......
  • java常见的排序算法(冒泡排序、选择排序、插入排序、shell排序、归并排序、堆排序、快
    (文章目录)本文简单的介绍了java常见的几种排序。所有的排序均是一个数组由小到大进行排序。一、冒泡排序1、效率表现和适用范围效率O(n²)适用于排序小列表2、算法实现publicvoidbubbleSortArray(int[]a){ intn=a.length; for(inti=1;i<n;i++){ fo......
  • RDIFramework.NET敏捷开发框架 ━ 工作流程组件介绍
    RDIFramework.NET,基于全新.NETFramework与.NETCore的快速信息化系统敏捷开发、整合框架,给用户和开发者最佳的.Net框架部署方案。为企业快速构建垮平台、企业级的应用提供了强大支持。1、RDIFramework.NET敏捷开发框架介绍RDIFramework.NET敏捷开发框架,是我司重磅推出的基于全新.N......
  • Java 实战介绍 Cookie 和 Session 的区别
    HTTP是一种不保存状态的协议,即无状态协议,HTTP协议不会保存请求和响应之间的通信状态,协议对于发送过的请求和响应都不会做持久化处理。无状态协议减少了对服务压力,如果一个服务器需要处理百万级用户的请求状态,对服务器的压力无疑的是巨大的。无状态的HTTP由于其简单和易用性......
  • 【专题介绍】音视频+
    音视频+从音视频编解码到网络传输的进一步降低时延;从智能硬件的开发到内容生产端与消费端的升级;从客户端建设到服务质量与体验的提升……音视频领域内的方方面面都在不断向前推进,助力着一个又一个行业从初生到走向成熟,或是加速转型,如:智慧医疗、工业/IoT、游戏、影视行业等等。「音......
  • Linux日志切割神器logrotate原理介绍和配置详解
    1、原理介绍create这也就是默认的方案,可以通过create命令配置文件的权限和属组设置;这个方案的思路是重命名原日志文件,创建新的日志文件。详细步骤如下:重命名正在输出日志文件,因为重命名只修改目录以及文件的名称,而进程操作文件使用的是inode,所以并不影响原程序继续输出日志......
  • 二、git介绍
    1.工作区和暂存区工作区: 就是在电脑上看到的目录,比如目录下testgit里的文件(.git隐藏目录版本库除外)。 或者以后需要再新建的目录文件等等都属于工作区范畴。版本库(Repository): 工作区有一个隐藏目录.git,这个不属于工作区,这是版本库。 其中版本库里面存了很多......
  • BRP EDI 项目 Excel方案开源介绍
    近期为了帮助广大用户更好地使用EDI系统,我们根据以往的项目实施经验,将成熟的EDI项目进行开源。用户安装好知行之桥EDI系统之后,只需要下载我们整理好的示例代码,并放置在知行之桥指定的工作区中,即可开始使用。今天的文章主要为大家介绍BRPEDI项目,了解如何获取开源的项目代码以及......
  • gtest框架的介绍与应用
    【摘要】在本文中,作者根据之前使用gtest框架进行测试的经验,总结了一些使用方式和案例。在这些案例中,我们可以了解到gtest框架的基本使用方法以及在我们日常测试中的应用,同时也能促进我们对于百度的btest的了解。在我们之后的测试工作中,可以根据各个项目的特点以及gtest、btest等......