- 博客(196)
- 资源 (11)
- 收藏
- 关注
原创 召回系统介绍
Lucene的倒排索引由 Term Index -> TermDictionary -> Posting List 三层组成,倒排检索实际上就是通过分词Term查询到倒排拉链,然后对所有拉链进行合并。Term-> Posting List,可以直接通过B+树来完成(对Term创建索引,叶子结点存储拉链的磁盘位置+长度),但是数据量较大时Term索引无法完整放在内存里,因此Lucene加了一个TermIndex,FST有限状态机转换器(类似Trie树),为了进一步压缩空间,Trie树里不存储所有Term,只包
2024-12-17 23:58:21
134
原创 LruCache(本地cache)生产环境中遇到的问题及改进
读cache时使用零拷贝机制,对缓存数据增加原子变量的引用计数,每次获取数据时引用计数+1,释放数据时-1,计数为0且达到过期时间时从cache中清除,防止内存泄漏。问题:并发读写的LruCache使用锁保护,单机qs过高时锁竞争严重,很多时间消耗在锁等待上,导致耗时增长。问题:单机qps增加时请求摘要后端,耗时也会增加,因为超过了后端处理能力(最大qps,存在任务堆积)。
2024-12-16 15:23:09
268
原创 向量检索原理
查询阶段:从指定起始点A开始,从相邻点(未访问过的)中选择m个距离查询向量Q最近的点加入到结果集中,所有相邻点加入候选队列,从候选中选择距离Q最近的点B,继续选择它最近m个相邻点,如果新发现的相邻点距离比原有结果集的更小,替换结果集中的点,重复上述过程,直到候选集中点都被访问过。距离计算方式有对称距离计算SDC和非对称距离计算ADC,q(x), q(y)是向量x,y编码后的向量,对称距离计算:离线计算出样本库中所有编码向量的距离表,实际计算x,y距离时直接查表即可,速度非常快但是放大了误差。
2024-12-11 16:44:47
190
原创 银行数字转文字
/一十二亿零四百五十万零一百零九亿一千二百零四万五千零一。//一十二亿三千四百五十六万七千八百零九。//一十二亿三千四百五十六万零九十。//一十二亿零四百五十万零一百零九。
2024-12-10 21:10:53
57
原创 系统设计 总结
缓存穿透:数据既不在缓存,也不在数据库中。一般由于业务误操作删除了缓存和数据库中数据,或者非法数据,比如恶意攻击。雪崩:大量缓存数据同时过期,或缓存服务器故障,会有大量请求同时打到数据库。击穿:属于雪崩的一种,热点数据过期或者系统资源限制被淘汰掉(lru)。
2024-11-28 11:11:47
153
原创 【双buffer无锁设计】
使用两个指针,一个指针指向当前使用的数据版本,所有读线程通过该指针读取数据,另一个是备份指针,写线程通过该指针写入,当写操作完成后对两个指针进行切换,完成数据更新。直接切换会导致读线程获取到的数据失效,甚至可能访问的无效内存导致出core,因此通过智能指针封装这两个指针,当读指针的引用计数为1没有读线程使用时切换两个指针。对于同一请求会话里中途会不会出现指针切换导致前后数据不一致,可以将数据指针(智能指针)存放在Context对象里,从Context中取用数据。【双buffer无锁设计】
2024-11-18 15:25:52
188
1
原创 性能优化篇
因为 ProtoBuf 采用的是 Arena 内存分配器策略,有些场景会比 C++的 Class 内存管理复杂,当有大量内存分配和释放的时候会比 Class 的性能差很多。而且 Protobuf 会不断分配和回收小内存对象,持续地分配和删除小内存对象导致产生内存碎片,降低程序的内存使用率,尤其是当协议中包含 string 类型的时候,性能差距可能有几倍。内存碎片:频繁分配和释放不同大小的对象,可能导致内存碎片,降低内存的使用效率。
2024-06-17 17:42:27
264
原创 lucene原理
一个索引中包含多个段,段与段之间相互独立。由于Lucene进行关键词检索时需要加载索引段进行下一步搜索,如果索引段较多会增加较大的I/O开销,减慢检索速度,因此写入时会通过段合并策略对不同的段进行合并。:保存了不同前缀对应的相应的Term及相应的倒排表信息,倒排表通过跳表实现快速查找,通过跳表能够跳过一些元素的方式对多条件查询交集、并集、差集之类的集合运算也提高了性能。:用于保存倒排索引Term的前缀,来快速定位.tim文件中属于这个Field的Term的位置,即上图中的aab、abd、bdc。
2024-06-16 23:20:53
1101
原创 cacheline一致性、内存序、volatile
CPU cache有三级,其中L1、L2是每个core私有的,L3是公共的,cacheline是CPU cache中最小的缓存单位,CPU访问主存中某个数据时会将cache line大小的数据全部读入cache中,目前主流CPU的cacheline大小是64B,比如访问一个long数组,cpu每次会将8个值一起读到cache中,利用这个特性我们可以快速遍历连续内存的数据,比如数组;但是对于非连续性内存比如链表,每次都要从主存中读取数据。
2023-06-13 15:33:39
306
原创 Redis相关知识
redis是kv存储系统,key为字符串类型,值为redis对象。由5种常用数据类型:String,List,Hash,Set,ZSet。底层没有直接使用C字符串,而是使用简单动态字符串实现。区别:(1)是二进制安全的,不会遇到'\0'而终止,可以存储图像和序列化对象;(2)结构中有表示长度的字段,获取字符串长度时间复杂度时O(1);(3)空间不足时会自动扩容,大小小于1M时每次扩容一倍空间,大小大于等于1M时,每次扩容1M。
2023-05-11 23:35:51
632
原创 Kafka相关知识
将每个Topic划分为多个分区Partition,每个分区时一组有序的消息日志,分区内每条消息都会关联一个连续的数字ID即offset,生产的一条消息只会送到一个分区上。topic是逻辑概念Partition是物理概念对用户透明,生产者只需要关心消息投递到哪个topic上消费者只需要关心在哪个topic行订阅数据。为了提高每个分区的可用性,分区也存在多个副本。图中相同颜色的分区互为副本。kafka存在两种模式:pull和pull模式。
2023-05-06 20:09:39
752
原创 操作系统 知识点
对于32位系统虚拟内存空间有4G,其中系统内存占高位地址的1G,进程内存最多占用3G,进程内部从低位到高位依次是.data段,.bss段,堆,mmap,栈。linux系统下默认栈空间大小为10M,也就是系统最多分配300个线程(3G/10M)。线程切换时机:时间片用完;线程阻塞(如等待IO时间、sleep)线程切换后被移入就绪队列。
2023-05-03 18:32:08
142
1
原创 二分查找原理及使用场景
建议使用左闭右开区间[l, r)查找。二分查找的最后,索引l,r会落到右区间第一个元素位置。因此但凡是能够见数组分成左右两个区间的都能应用二分查找法。
2023-04-12 14:46:14
592
原创 无锁容器 c++
当生产者消费者数目较多时,用锁实现的线程安全容器锁竞争激烈,上下文切换严重带来较大的性能开销。无所容器实现的关键是为容器的每个槽位设置状态,拿到期望状态的线程通过CAS将状态修改,其他线程因拿不到期望状态二锁死在循环里。
2023-03-31 10:25:49
289
原创 dp分类--状态枚举
股票系列常见提问方式:给定n天的股票价格,用户可以买入和卖出股票且交易次数(买入+卖出算一次交易)最多k次,计算可以获得的最大收益?注意不同于取元素,每天的操作是不同的因此对应买入和卖出操作将元素状态分为有没有持股,所以元素状态必须作为dp状态;
2023-03-19 00:02:35
263
原创 函数定义与声明
在C98中inline用于函数内联,但是在C++11以及更高的版本中编译器内联函数不再完全参考inline关键字。inline是一种弱修饰符,可修饰函数和命名空间(C++17)。
2023-01-19 16:10:27
210
原创 并行下的效率与安全
cacheline被读取进来后会拷贝到内核私有的L1/L2cache下,当原子变量被修改后,会通知cpu的其他核心来同步变量所在的cacheline(cpu一致性同步)。这就存在falsesharing现象当某个变量被多个核心共享时,一个核心对其进行修改就会导致其所在的cacheline失效,需要重新从内存读取,cacheline中的其他变量也要等待缓存同步而变慢,严重影响整体性能。......
2022-07-24 21:51:00
367
原创 设计模式--策略模式
多态:同一类型的指针或引用在指向不同子类对象时可以表现出不同的行为。我们知道多态最常见的实现方式就是基类定义虚函数,派生类通过继承基类的函数后,对基类函数重写来实现。但是在项目中,往往出现表现多态的类本身改动很小,而该类簇的行为改动频繁,(或者可能行为的实现时算法同学负责,而多态类时我们架构同学负责)那么我们把多态类视为使用行为的上下文,把行为从中抽象出来定义成行为类,这就引出了多态实现的另一种方式:通过继承基类的行为对象成员,然后派生类将成员初始化为不同的行为派生类对象,这样在调用行为类对象的方法时就能表
2021-06-27 19:49:43
212
原创 设计模式--工厂模式
文章目录使用场景工厂模式应用很广,重构场景:冗长switch:如果case比较多而且每个case处理处理程序比较复杂(即使将其封装到函数也不容易管理,而且可读性不高,每次要重新阅读case),都可以通过"简单工厂模式"优化:将//优化前{switch(cmd) {case HTTP_REQ_CMD: process_http_req(); break;case RPC_REQ_CMD: process_rpc_req(); break;case:...}//优化后cla
2021-06-20 20:36:35
486
1
原创 c++探险--多态类的内存分布
父类没有虚函数我们都知道子类在继承父类的时候,会将父类的变量和虚表指针继承下来保存到自己的内存里(即使父类private变量的内存也会继承下来,只会无法访问到),也就是子类对象内存中存储着一个父类对象。如果使菱形继承,那么"菱形"底部的类就会存储两份"菱形"顶端的类对象内存,通过虚继承可优化成一份,暂且不表。class Base {public: int a;private: int b;};class Sub : public Base {int c;};#mermaid-svg.
2021-06-20 18:15:27
292
1
原创 写出优雅代码
目录一. 封装,继承,多态封装继承多态二. 设计原则单一职责一. 封装,继承,多态封装尽可能隐藏一个模块的实现细节。原因:增加调用者负担,使用者在使用你的类时还要知道实现细节。耦合性。比如类内部有个成员是vector,那么外部应该用push_back等方法来操作,有一天需要换城map,那么所有调用方的代码都得改。应该对外界提供访问数据的方法(getter、setter);而不是直接将数据等实现细节暴露出去。继承不能仅仅因为is-a和is-kind-of就定义为继承关系,必须是派生类能够适
2021-05-27 02:11:57
160
原创 再探git
–cached == --stagednot staged:文件已经存在暂存区,工作区文件修改了但还没add到Stagenot tracked:工作区新建的文件,从未添加到Stage。git status : 查看暂存区和本地仓库的状态。git ls-files : 显示暂存区的文件,git commit/push之后,记录仍在。–cached : 显示暂存区里的文件(默认)–deleted:显示从暂存区删除的文件(git rm file :从Stage中删除)–modified:显示.
2021-05-09 16:47:09
292
原创 桶原理的应用
鸽笼原理计算最大间距问题:要求线性时间复杂度下计算数组元素在排序后的最大间距。如果直接对数组排序那么时间复杂度是nlogn,这里使用桶,设置n+1个桶这样n个元素放入后至少出现一个空桶,这就使得不同桶之间的元素差大于同内部的元素差(因为空桶两侧的桶元素差>=width,桶内元素差<width)。计算所有相邻非空桶之间元素差值(相邻桶之间的元素差可能大于空桶两侧的桶元素之间元素差)。int largestDiff(vector<int>& nums) { int.
2021-01-09 01:46:40
272
原创 单调栈总结
leet"255. 验证前序遍历序列二叉搜索树"题解:先序遍历搜索树,只有左子树时元素是单调递减的,但存在某一结点的右子树就不满足单调。如5/ \2 6/ \1 3输入: [5,2,6,1,3]输出: false先序遍历[5,2,1,3,6]。只有左子树[5,2,1],加入2的右子树变成[5,2,1,3]。因此为了保持栈的单调,元素大于栈顶元素,弹出栈中小于当前结点的值,并把当前节点入栈,变成[5,3],这时栈中又只剩下左子树,满足单调。最后一个弹出栈2的是当前节点3的根节点。
2020-12-09 10:17:08
257
2
原创 计算字符串表达式
整体思路:按照“符号-数字”处理字符串,将+/-运算看作数字的符号不单独运算,因此不需要考虑符号的优先级问题,在遇到非数字符号或者到达字符串结尾时处理上一个“符号-数字”组合。将括号内容看作一个数字,递归处理,遇到“)”表示当前是计算的括号内容,因此直接将结果返回,一定注意共用一个索引,用来跳过括号内容。class Solution {public: int helper(string s, int& i) { int n = s.size(), num = 0; stack<i
2020-09-30 15:34:33
691
原创 并查集原理及应用
并查集树形的数据结构,每个集合有其代表节点,代表节点相同的元素属于同一集合。find:通过查找节点的代表节点,判断节点所属集合。union:合并两集合,小集合合并到大集合,使用大集合的代表节点。class UnionFindSet {private: unordered_map<int, int> fatherMap; unordered_map<int, int> nodesNum;public: UnionFindSet(vector<int> ve
2020-05-20 18:26:04
244
原创 c++引用
c++引用包含左值引用和右值引用,因为引用都是变量,因此右值引用是左值。左值指变量,右值指临时对象,字面值(16,“string”,13+2)。当函数参数为T&&时(其中T时模板类型),是万能引用,传入参数是左值,T&&就变成左值引用,否则T&&变成右值引用。template<typename T> void f(T&&a...
2019-12-24 11:55:18
218
原创 TrieTree
class TrieTree{public: //定义trie树节点,26个字符是定义在分支上。 struct Node { int across; int end; shared_ptr<Node> nexts[26]; Node() :across(0), end(0) {} }; typedef shared_ptr<Node> Node...
2019-12-23 20:37:40
229
原创 图
图的结构定义(邻接表)struct Node{ int id;//节点id,如果节点本身有值还可以加val字段。 bool visit;//是否访问 vector<shared_ptr<Node>> nexts;//从本节点出发的下一个节点,有向无向均可。 Node(int _id) :id(_id), visit(false) {}};struct Edg...
2019-12-23 16:21:12
334
原创 哈希表
哈希表又称散列表,存储键值对,主要操作有插入,删除,查找。哈希表底层是一个数组,首先将key通过哈希函数计算哈希值,也即数组下标,然后对位置上的元素执行插入删除,查询。三种操作时间复杂度均为O(1)O(1)O(1),耗时操作在哈希函数计算和哈希冲突的处理上。哈希函数(*)哈希函数的要求是,映射均匀,降低哈希冲突的几率;计算简单,节省时间。直接定址法使用key的线性函数作为哈希函数,H(k...
2019-12-21 20:54:30
345
原创 模板相关
一. 编译过程首先介绍C++程序的编译过程。编译器以源文件为编译单元,编译过程分为四个阶段:预处理,编译,汇编,链接。预处理:处理头文件和宏定义。首先根据寻找源文件中所包含的头文件,进入头文件进行宏替换,根据条件编译修改源程序。然后把头文件的内容全部添加到当前原文件里,形成一个中间c文件。编译:对中间的c文件进行语法检查,并将源代码编译成汇编文件。汇编:将汇编翻译成二进制的机器码...
2019-12-20 17:28:30
206
xmapp+phpwind+agileone.zip
2019-12-05
nccl-2.4.8-1-x86_64.pkg.tar.xz
2019-07-28
QT实现wav音频文件读写
2018-09-11
c++版神经网络实现
2018-06-19
Deep Learning with TensorFlow
2018-04-11
stc15w4k58s4控制的直立车(带角度闭环、速度闭环,蓝牙调试、OLED显示等)
2016-09-11
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人