这是啥设计模式-单例模式

server/2024/10/18 8:38:24/

召回算法中有一个叫做I2I的召回方式,给定一个Item,返回跟这个Item相似的topK个Item,这种相似关系一般在离线就计算好了,以KV的方式存储下来

<item1, [item2, item3,item4]>
<item2, [item1, item5,item6]>
...

我们使用的时候也加载成kv的格式就可以了

1. 基础实现

我们要提供这样一个数据,同样需要定义一个接口

using KvPair = std::unordered_map<std::string, std::vector<std::string>>;
class Kv{
public:Kv() = default;void update(const std::string& kvPath) {auto kv = std::make_shared<KvPair>();kv->emplace("item1", std::vector<std::string>{"item1", "item2", "item3"});kv->emplace("item2", std::vector<std::string>{"item1", "item4"});kv->emplace("item3", std::vector<std::string>{"item1"});{// 使用 lock_guard 锁定互斥锁std::lock_guard<std::mutex> lock(mtx);m_kv.swap(kv);}}std::vector<std::string> getTopK(const std::string& item) {auto iter = m_kv->find(item);if(iter != m_kv->end()) {return iter->second;}return std::vector<std::string>();}~Kv() = default;
private:std::shared_ptr<KvPair> m_kv = std::make_shared<KvPair>();// 创建一个互斥锁std::mutex mtx;
}

我们实现了两个方法,一个是数据更新的方法,一个是获取TopK的方法。客户端调用也非常的简单

auto kv = new Kv();
Kv->update('kv.pb');
auto items = Kv->getItems("item1");

2. 多处调用

现在有好几个地方都会调用这份kv数据,我们简单实现一下,第一个是test1.cpp文件

// test1.cpp
void test1() {auto kv = new Kv();Kv->update('kv.pb');auto items = Kv->getItems("item1");
}

第二个地方是test2.cpp文件

// test2.cpp
void test2() {auto kv = new Kv();Kv->update('kv.pb');auto items = Kv->getItems("item1");
}

这么实现的问题非常的明显,就是每个地方调用都需要加载一次数据,但是这份数据不会发生变化,谁调用都是一样的。

3. 单例模式

一个简单的想法就是让这个类对象只有一个,首先构造函数不能暴露出来,不然就可以定义多个对象了

class Kv{
private:// 构造函数和析构函数都定义为private,防止被外部调用Kv() = default;~Kv() = default;// 将其拷贝构造和赋值构造成为私有函数, 禁止外部拷贝和赋值Kv(const Kv &kv) = delete;const Kv &operator=(const Kv &kv) = delete;
public:// 类方法,类直接调用static Kv *GetInstance();
}

问题是构造函数都变成私有的了,该如何实例化这个对象呢?我们可以定义一个函数来代替构造函数,在这个函数里面我们设置一个标识符,表示这个对象是否已经初始化过了,如果初始化过了,就返回之前构造出来的对象,否则就进行构造初始化

Kv* Kv::kvInstance{nullptr};
std::mutex Kv::mutexKvInstance;
Kv* Kv::GetInstance()
{std::lock_guard<std::mutex> lock(mutexKvInstance);if (kvInstance== nullptr) // 如果是nullptr说明还没有被初始化过{kvInstance= new Kv();}return kvInstance; // 返回唯一的对象
}

还有一种更有有趣的实现方法,极力推荐

// 注意:不能返回指针的引用,否则存在外部被修改的风险!
Kv& Kv::GetInstance()
{/*** 局部静态特性的方式实现单实例。静态局部变量只在当前函数内有效,其他函数无法访问。* 静态局部变量只在第一次被调用的时候初始化,也存储在静态存储区,生命周期从第一次被初始化起至程序结束止。*/static Kv kv;return kv;
}

4. 单例模式python

import threading
class Singleton(object):_instance_lock = threading.Lock()def __init__(self):pass@classmethoddef instance(cls, *args, **kwargs):with Singleton._instance_lock:if not hasattr(Singleton, "_instance"):Singleton._instance = Singleton(*args, **kwargs)return Singleton._instance

http://www.ppmy.cn/server/104446.html

相关文章

docker启动ES(elasticsearch:7.17.23)

docker直接启动es&#xff0c;报如下错误 2024-08-22 10:52:27 ERROR: [1] bootstrap checks failed. You must address the points described in the following [1] lines before starting Elasticsearch. 2024-08-22 10:52:27 bootstrap check failure [1] of [1]: the defa…

jmeter 请求带证书的 客户端的SSL/TLS证书和私钥https请求

背景: 工作需要对下面接口进行压测,走的是https 带证书的请求 curl -v -X POST -u acsuser:admin20232023 --cert /home/bdgw/ssl/server.crt --key /home/bdgw/ssl/server.key -H "Content-Type: application/json" -d {"thirdAlarmId":"comp2…

更换域名后图片不显示

问题&#xff1a;系统更换域名后&#xff0c;图片不显示了&#xff1b; 原因&#xff1a;系统中图片是带域名存储在数据的&#xff0c;所以更换域名后&#xff0c;图片地址还是以前的域名&#xff0c;所以访问不到&#xff1b; 解决方法&#xff1a; 以下两个方法都是只能更…

git如何将多个提交合并为一个提交

目录 第一种&#xff1a;使用git rebase命令 第二种&#xff1a;使用git reset命令 重新提交 第一种&#xff1a;使用git rebase命令 使用以下命令的其中一种启动交互式 rebase git rebase -i 你想要合并提交的父提交的哈希值git rebase -i <commit-hash>^ &#…

PCL-基于超体聚类的LCCP点云分割

目录 一、LCCP方法二、代码实现三、实验结果四、总结五、相关链接 一、LCCP方法 LCCP指的是Local Convexity-Constrained Patch&#xff0c;即局部凸约束补丁的意思。LCCP方法的基本思想是在图像中找到局部区域内的凸结构&#xff0c;并将这些结构用于分割图像或提取特征。这种…

mac安装ipa包【金铲铲为例】

mac安装ipa包 安装PlayCover 链接&#xff1a;https://github.com/PlayCover/PlayCover 1、点最新Releases 2、cmd ↓&#xff0c;拉到最下面下载dmg 3、安装 图标拖拽到Applications里 IPA下载 以金铲铲为例&#xff0c;良心砸壳包站点&#xff0c;有能力可以支持一下…

day40——IO模型补充

2.4 epoll模型 epoll模型只有linux系统才有 epoll模型只有从linxu内核2.4版本之后才有 epoll从2.4内核到目前的4.X内核&#xff0c;没有更新的模型了&#xff0c;说明epoll模型本身已经很完美了 select的问题&#xff1a; 监视列表无法扩容 监视列表和返回的激活列表混在了…

【计算机三级-数据库技术】数据库后台编程技术

内容提要 1、掌握存储过程的定义与使用 2、掌握用户定义函数的创建与使用 3、掌握触发器的定义与使用 4、掌握游标的定义与使用 第一节 存储过程 使用T-SQL语言编写&#xff0c;有两种方式存储&#xff1a; 在客户端存储代码通过客户端程序或SQL命令向DBMS发出操作请求&…