
代码staticDATA_MANAGER:LazyMutexDataManagerLazy::new(||Mutex::new(DataManager::new()));这行代码实现了一个线程安全的全局单例模式拆解如下static DATA_MANAGER— 全局静态变量在整个程序运行期间只有一份DATA_MANAGER所有代码共享同一个实例。LazyT— 惰性初始化懒加载once_cell::sync::Lazy保证初始化闭包|| Mutex::new(DataManager::new())只会在第一次被访问时执行一次之后每次访问都返回已经初始化好的值。不是程序启动时就创建而是用到时才创建只创建一次线程安全后续访问直接复用MutexDataManager— 互斥锁Mutex互斥锁保证多线程环境下对DataManager的访问是互斥的——同一时刻只有一个线程能持有锁并操作数据避免数据竞争data race。DataManager::new()— 实际数据真正的数据管理器实例持有movie_map、user_map、genre_reverse_index三张核心哈希表。详细例子假设有一个电影推荐系统 Web 服务同时有 3 个用户请求进来分别由 3 个线程处理时间线 → 线程A查电影1 ──── 等锁 ──┬── 拿到锁 → 查movie_map → 释放锁 线程B查用户5 ──── 等锁 ──┤ ├── 拿到锁 → 查user_map → 释放锁 线程C查类型 ──── 等锁 ──┘ └── 拿到锁 → 查genre_index → 释放锁 首次访问以init_data_manager为例pubfninit_data_manager(base_path:str){letmutdmDATA_MANAGER.lock().unwrap();// ① 第一次访问触发 Lazy 初始化// ② Lazy 执行闭包Mutex::new(DataManager::new())创建空的 movie_map、user_map、genre_reverse_index// ③ lock() 获取锁拿到可变引用 mut DataManagerdm.load_data(movie_path,link_path,rating_path,...);// ④ 加载所有CSV数据}// ⑤ dm 离开作用域自动释放锁// 之后任何线程再访问 DATA_MANAGER.lock()Lazy 不会再初始化直接返回已有的 Mutex运行时查询多线程并发场景// 线程1查询某部电影fnhandle_get_movie(movie_id:i32){letdmDATA_MANAGER.lock().unwrap();// 获取锁letmoviedm.get_movie_by_id(movie_id);// 查询println!({:?},movie);}// 锁自动释放// 线程2按类型查询电影同时进行但需要排队等锁fnhandle_get_by_genre(genre:str){letdmDATA_MANAGER.lock().unwrap();// 等线程1释放锁后才能获取letmoviesdm.get_movies_by_genre(genre,10,rating);println!({:?},movies);}这个模式解决了什么问题问题解决方案数据只加载一次避免重复读取CSV文件Lazy保证只初始化一次多线程同时访问同一份数据Mutex保证互斥访问全局可访问不需要到处传参static全局变量 get_data_manager()不使用时零开销Lazy在首次访问前不占用资源简单类比就像整个程序有一本共享的百科全书电影、用户、评分数据所有线程都能查阅但同一时刻只允许一个人翻书而且这本书只在第一次有人要看时才从仓库搬出来。