【Golang开源项目】Golang高性能内存缓存库BigCache设计与分析
项目地址
BigCache 是一个快速,支持并发访问,自淘汰的内存型缓存,可以在存储大量元素时依然保持高性能。BigCache将元素保存在堆上却避免了GC的开销。
背景介绍
BigCache的作者在项目里遇到了如下的需求:
- 支持
http协议 - 支持 10 k 10k 10kRPS ,其中读写各占一半
cache缓存至少 10 10 10分钟- 平均 r t = 5 m s , p 99 < = 10 m s , p 999 < = 400 m s rt=5ms,p99<=10ms,p999<=400ms rt=5ms,p99<=10ms,p999<=400ms
开发的缓存库需要保证: - 即使有百万的缓存对象速度也要很快
- 支持高并发访问
- 支持过期自动删除
简单入门
func Test_BigCache(t *testing.T) {cache, _ := bigcache.New(context.Background(), bigcache.DefaultConfig(10*time.Minute)) //定义cachecache.Set("my-unique-key", []byte("value")) //设置k,v键值对entry, _ := cache.Get("my-unique-key") //获取k,v键值对t.Log(string(entry))
}
配置文件
config字段说明
| 字段名 | 类型 | 含义 |
|---|---|---|
| Shards | int | 缓存分片数,值必须是 2 的幂 |
| LifeWindow | time.Duration | 条目可以被逐出的时间,近似可以理解为缓存时间 |
| CleanWindow | time.Duration | 删除过期条目(清理)之间的间隔。如果设置为 <= 0,则不执行任何操作。设置为 < 1 秒会适得其反,因为 bigcache 的分辨率为 1 秒。 |
| MaxEntriesInWindow | int | 生命周期窗口中的最大条目数。仅用于计算缓存分片的初始大小。如果设置了适当的值,则不会发生额外的内存分配。 |
| MaxEntrySize | int | 条目的最大大小(以字节为单位)。仅用于计算缓存分片的初始大小。 |
| StatsEnabled | bool | StatsEnabled如果为true,则计算请求缓存资源的次数。 |
| Verbose | bool | 是否以详细模式打印有关新内存分配的信息 |
| Hasher | Hasher | 哈希程序用于在字符串键和无符号 64 位整数之间进行映射,默认情况下使用 fnv64 哈希。 |
| HardMaxCacheSize | int | 是BytesQueue 大小的限制 MB。它可以防止应用程序占用计算机上的所有可用内存,从而防止运行 OOM Killer。 |
| OnRemove | func(key string, entry []byte) | OnRemove 是当最旧的条目由于过期时间或没有为新条目留出空间或调用 delete 而被删除时触发的回调。如果指定了 OnRemoveWithMetadata,则忽略。 |
| OnRemoveWithMetadata | func(key string, entry []byte, keyMetadata Metadata) | OnRemoveWithMetadata 是当最旧的条目由于过期时间或没有为新条目留出空间或调用 delete 而被删除时触发的回调,携带有关该特定条目的详细信息的结构。 |
| OnRemoveWithReason | func(key string, entry []byte, reason RemoveReason) | OnRemoveWithReason 是当最旧的条目由于过期时间或没有为新条目留出空间或调用了 delete 而被删除时触发的回调,将传递一个表示原因的常量。如果指定了 OnRemove,则忽略。 |
| onRemoveFilter | int | 和OnRemoveWithReason一起使用,阻止 bigcache 解包它们,从而节省 CPU。 |
| Logger | Logger | 日志记录接口 |
说明:
- LifeWindow 是一个时间。在此之后,条目可以称为死条目,但不能删除。
- CleanWindow 是一个时间。在此之后,将删除所有无效条目,但不会删除仍具有生命的条目。
- HardMaxCacheSize 默认值为 0,表示大小不受限制。当限制高于 0 并达到时,新条目将覆盖最旧的条目。由于 Shards 的额外内存,最大内存消耗将大于 HardMaxCacheSize。每个分片都会消耗额外的内存来映射键和统计信息 (map[uint64]uint32),此映射的大小等于缓存中的条目数 ~ 2×(64+32)×n 位 + 开销或映射本身。
- OnRemove,OnRemoveWithMetadata ,OnRemoveWithReason 这三个跟删除有关的属性默认值为 nil,表示没有回调,并且会阻止解开最早的条目。
配置代码文件
// Config for BigCache
type Config struct {// Number of cache shards, value must be a power of twoShards int// Time after which entry can be evictedLifeWindow time.Duration// Interval between removing expired entries (clean up).// If set to <= 0 then no action is performed. Setting to < 1 second is counterproductive — bigcache has a one second resolution.CleanWindow time.Duration// Max number of entries in life window. Used only to calculate initial size for cache shards.// When proper value is set then additional memory allocation does not occur.MaxEntriesInWindow int// Max size of entry in bytes. Used only to calculate initial size for cache shards.MaxEntrySize int// StatsEnabled if true calculate the number of times a cached resource was requested.StatsEnabled bool// Verbose mode prints information about new memory allocationVerbose bool// Hasher used to map between string keys and unsigned 64bit integers, by default fnv64 hashing is used.Hasher Hasher// HardMaxCacheSize is a limit for BytesQueue size in MB.// It can protect application from consuming all available memory on machine, therefore from running OOM Killer.// Default value is 0 which means unlimited size. When the limit is higher than 0 and reached then// the oldest entries are overridden for the new ones. The max memory consumption will be bigger than// HardMaxCacheSize due to Shards' s additional memory. Every Shard consumes additional memory for map of keys// and statistics (map[uint64]uint32) the size of this map is equal to number of entries in// cache ~ 2×(64+32)×n bits + overhead or map itself.HardMaxCacheSize int// OnRemove is a callback fired when the oldest entry is removed because of its expiration time or no space left// for the new entry, or because delete was called.// Default value is nil which means no callback and it prevents from unwrapping the oldest entry.// ignored if OnRemoveWithMetadata is specified.OnRemove func(key string, entry []byte)// OnRemoveWithMetadata is a callback fired when the oldest entry is removed because of its expiration time or no space left// for the new entry, or because delete was called. A structure representing details about that specific entry.// Default value is nil which means no callback and it prevents from unwrapping the oldest entry.OnRemoveWithMetadata func(key string, entry []byte, keyMetadata Metadata)// OnRemoveWithReason is a callback fired when the oldest entry is removed because of its expiration time or no space left// for the new entry, or because delete was called. A constant representing the reason will be passed through.// Default value is nil which means no callback and it prevents from unwrapping the oldest entry.// Ignored if OnRemove is specified.OnRemoveWithReason func(key string, entry []byte, reason RemoveReason)onRemoveFilter int// Logger is a logging interface and used in combination with `Verbose`// Defaults to `DefaultLogger()`Logger Logger
}
默认配置
DefaultConfig 使用默认值初始化配置。当可以提前预测 BigCache 的负载时,最好使用自定义配置。
| 字段名 | 值 | 含义 |
|---|---|---|
| Shards | 1024 | 缓存分片数是1024 |
| LifeWindow | eviction | 自定义过期时间 |
| CleanWindow | 1 * time.Second | 每隔1秒就清理失效数据 |
| MaxEntriesInWindow | 1000 * 10 * 60 | 生命周期窗口中的最大条目数为6e5 |
| MaxEntrySize | 500 | 条目的最大大小为500字节 |
| StatsEnabled | false | 不计算请求缓存资源的次数 |
| Verbose | true | 以详细模式打印有关新内存分配的信息 |
| Hasher | fnv64 | 哈希程序,fnv64 哈希 |
| HardMaxCacheSize | 0 | BytesQueue 大小无限制 |
| Logger | DefaultLogger | 日志记录接口 |
优点:支持自定义过期时间,清理失效数据的间隔为最小间隔、效率高
缺点:BytesQueue 大小无限制,容易造成内存占用过高
默认配置代码:
func DefaultConfig(eviction time.Duration) Config {return Config{Shards: 1024,LifeWindow: eviction,CleanWindow: 1 * time.Second,MaxEntriesInWindow: 1000 * 10 * 60,MaxEntrySize: 500,StatsEnabled: false,Verbose: true,Hasher: newDefaultHasher(),HardMaxCacheSize: 0,Logger: DefaultLogger(),}
}
数据结构
前提说明:BigCache 是快速、并发、逐出缓存,旨在保留大量条目而不影响性能。它将条目保留在堆上,但省略了它们的 GC。为了实现这一点,操作发生在字节数组上,因此在大多数用例中,都需要在缓存前面进行条目**(反序列化)**。
BigCache数据结构
| 字段名 | 类型 | 含义 |
|---|---|---|
| shards | []*cacheShard | 缓存分片数据 |
| lifeWindow | uint64 | 缓存时间,对应配置里的LifeWindow |
| clock | clock | 时间计算函数 |
| hash | Hasher | 哈希函数 |
| config | Config | 配置文件 |
| shardMask | uint64 | 值为(config.Shards-1),寻找分片位置时使用的参数,可以理解为对config.Shards取余后的最大值 |
| close | chan struct{} | 关闭通道 |
type BigCache struct {shards []*cacheShardlifeWindow uint64clock clockhash Hasherconfig ConfigshardMask uint64close chan struct{}
}
cacheShard数据结构
| 字段名 | 类型 | 含义 |
|---|---|---|
| hashmap | map[uint64]uint32 | 索引列表,key为存储的key,value为该key在entries里的位置 |
| entries | queue.BytesQueue | 实际数据存储的地方 |
| lock | sync.RWMutex | 互斥锁,用于并发读写 |
| entryBuffer | []byte | 入口缓冲区 |
| onRemove | onRemoveCallback | 删除回调函数 |
| isVerbose | bool | 是否详细模式打印有关新内存分配的信息 |
| statsEnabled | bool | 是否计算请求缓存资源的次数 |
| logger | Logger | 日志记录函数 |
| clock | clock | 时间计算函数 |
| lifeWindow | uint64 | 缓存时间,对应配置里的LifeWindow |
| hashmapStats | map[uint64]uint32 | 存储缓存请求次数 |
| stats | Stats | 存储缓存统计信息 |
| cleanEnabled | bool | 是否可清理,由config.CleanWindow决定 |
type cacheShard struct {hashmap map[uint64]uint32entries queue.BytesQueuelock sync.RWMutexentryBuffer []byteonRemove onRemoveCallbackisVerbose boolstatsEnabled boollogger Loggerclock clocklifeWindow uint64hashmapStats map[uint64]uint32stats StatscleanEnabled bool
}
BytesQueue数据结构
BytesQueue 是一种基于 bytes 数组的 fifo 非线程安全队列类型。对于每个推送操作,都会返回条目的索引。它可用于稍后读取条目。
| 字段名 | 类型 | 含义 |
|---|---|---|
| full | bool | 队列是否已满 |
| array | []byte | 实际数据存储的地方 |
| capacity | int | 容量 |
| maxCapacity | int | 最大容量 |
| head | int | 队首位置 |
| tail | int | 下次可以插入的元素位置 |
| count | int | 当前存在的元素数量 |
| rightMargin | int | 右边界 |
| headerBuffer | []byte | 插入时的临时缓冲区 |
| verbose | bool | 是否详细模式打印有关新内存分配的信息 |
type BytesQueue struct {full boolarray []bytecapacity intmaxCapacity inthead inttail intcount intrightMargin intheaderBuffer []byteverbose bool
}
优秀设计
处理并发访问
设计点1:将数据打散后存储
通用解法: 缓存支持并发访问是很基本的要求,比较常见的解决访问是对缓存整体加读写锁,在同一时间只允许一个协程修改缓存内容。这样的缺点是锁可能会阻塞后续的操作,而且高频的加锁、解锁操作会导致缓存性能降低。
设计点: B i g C a c h e BigCache BigCache使用一个 s h a r d shard shard数组来存储数据,将数据打散到不同的 s h a r d shard shard里,每个 s h a r d shard shard里都有一个小的 l o c k lock lock,从而减小了锁的粒度,提高访问性能。
设计点2:打散数据过程中借助位运算加快计算速度
接下来看一下将某个数据放到缓存的过程的源代码:
// Set saves entry under the key
func (c *BigCache) Set(key string, entry []byte) error {hashedKey := c.hash.Sum64(key)shard := c.getShard(hashedKey)return shard.set(key, hashedKey, entry)
}
func (c *BigCache) getShard(hashedKey uint64) (shard *cacheShard) {return c.shards[hashedKey&c.shardMask]
}
可以得到 s e t set set的过程如下:
- 进行 h a s h hash hash操作,将 s t r i n g string string类型 k e y key key哈希为一个 u i n t 64 uint64 uint64类型的 h a s h e d K e y hashedKey hashedKey
- 根据 h a s h e d K e y hashedKey hashedKey做 s h a r d i n g sharding sharding,最后落到的 s h a r d shard shard的下标为 h a s h e d K e y % n hashedKey\%n hashedKey%n,其中 n n n是分片数量。理想情况下,每次请求会均匀地落在各自的分片上,单个 s h a r d shard shard的压力就会很小。
- 调用对应 s h a r d shard shard的set方法来设置缓存
设计点:
当 n n n为 2 2 2的幂次方的时候,对于任意的 x x x,下面的公式都成立的。
x m o d N = ( x & ( N − 1 ) ) x\ mod\ N = (x \& (N − 1)) x mod N=(x&(N−1))
所以可以借助位运算快速计算余数,因此倒推回去 缓存分片数必须要设置为 2 2 2的幂次方。
设计点3 避免栈上的内存分配
默认的哈希算法为 f n v 64 fnv64 fnv64算法,该算法采用位运算的方式在栈上运算,避免了在堆上分配内存
package bigcache// newDefaultHasher returns a new 64-bit FNV-1a Hasher which makes no memory allocations.
// Its Sum64 method will lay the value out in big-endian byte order.
// See https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function
func newDefaultHasher() Hasher {return fnv64a{}
}type fnv64a struct{}const (// offset64 FNVa offset basis. See https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function#FNV-1a_hashoffset64 = 14695981039346656037// prime64 FNVa prime value. See https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function#FNV-1a_hashprime64 = 1099511628211
)// Sum64 gets the string and returns its uint64 hash value.
func (f fnv64a) Sum64(key string) uint64 {var hash uint64 = offset64for i := 0; i < len(key); i++ {hash ^= uint64(key[i])hash *= prime64}return hash
}
减少GC开销
设计点1:利用go1.5+特性,减少GC扫描
g o l a n g golang golang里实现缓存最简单的方式是 m a p map map来存储元素,比如 m a p [ s t r i n g ] I t e m map[string]Item map[string]Item。
使用 m a p map map的缺点为垃圾回收器 G C GC GC会在标记阶段访问 m a p map map里的每一个元素,当 m a p map map里存储了大量数据的时候会降低程序性能。
B i g C a c h e BigCache BigCache使用了 g o 1.5 go1.5 go1.5版本以后的特性:如果使用的map的key和value中都不包含指针,那么GC会忽略这个map
具体而言, B i g C a c h e BigCache BigCache使用 m a p [ u i n t 64 ] u i n t 32 map[uint64]uint32 map[uint64]uint32
来存储数据,不包含指针, G C GC GC就会自动忽略这个 m a p map map。
m a p map map的 k e y key key存储的是缓存的 k e y key key经过 h a s h hash hash函数后得到的值
m a p map map的 v a l u e value value存储的是序列化后的数据在全局 [ ] b y t e []byte []byte中的下标。
因为 B i g C a c h e BigCache BigCache是将存入缓存的 v a l u e value value序列化为 b y t e byte byte数组,然后将该数组追加到全局的 b y t e byte byte数组里(说明:结合前面的打散思想可以得知一个 s h a r d shard shard对应一个全局的 b y t e byte byte数组)
这样做的缺点是删除元素的开销会很大,因此 B i g C a c h e BigCache BigCache里也没有提供删除指定 k e y key key的接口,删除元素靠的是全局的过期时间或是缓存的容量上限,是先进先出的队列类型的过期。
性能测试
项目开发者给出了项目和主流缓存方案的 B e n c h m a r k s Benchmarks Benchmarks结果和 G C GC GC测试结果
测试文件链接


参考
妙到颠毫: bigcache优化技巧
[译] Go开源项目BigCache如何加速并发访问以及避免高额的GC开销
相关文章:
【Golang开源项目】Golang高性能内存缓存库BigCache设计与分析
项目地址 BigCache 是一个快速,支持并发访问,自淘汰的内存型缓存,可以在存储大量元素时依然保持高性能。BigCache将元素保存在堆上却避免了GC的开销。 背景介绍 BigCache的作者在项目里遇到了如下的需求: 支持http协议支持 10…...
Elasticsearch 7.8.0从入门到精通
安装Elasticsearch 7.8.0 官网:Elasticsearch 7.8.0 | Elastic 大家下载所需要的安装包即可。然后解压缩: Elasticsearch是通过java编写的,所以自带jdk。多好,下载Elasticsearch赠送jdk 0.0,不过一般我们用自己的jdk…...
寻找最富裕的小家庭 - 华为OD统一考试
OD统一考试(C卷) 分值: 100分 题解: Java / Python / C++ 题目描述 在一棵树中,每个节点代表一个家庭成员,节点的数字表示其个人的财富值,一个节点及其直接相连的子节点被定义为一个小家庭现给你一棵树,请计算出最富裕的小家庭的财富和。 输入描述 第一行为一个数N,…...
ssm基于Java的药店药品信息管理系统的设计与实现论文
摘 要 传统信息的管理大部分依赖于管理人员的手工登记与管理,然而,随着近些年信息技术的迅猛发展,让许多比较老套的信息管理模式进行了更新迭代,药品信息因为其管理内容繁杂,管理数量繁多导致手工进行处理不能满足广大…...
Word插件-大珩助手-手写电子签名
手写签名 支持鼠标写,支持触摸屏写,点击画笔按钮切换橡皮擦,支持清空画板重写,点击在word中插入签名,可插入背景透明的签字图 素材库-保存签名 将写好的签字图复制粘贴到素材库中,以便永久使用ÿ…...
Edge扩展插件安装位置
根据所获取的信息,Microsoft Edge的扩展插件安装位置和配置方式可以通过不同的方法管理。以下是一个大纲,概述了如何配置和管理Edge扩展插件: Edge扩展插件安装和管理大纲 了解扩展插件的安装模式 安装模式的选项:了解allowed、…...
Git将本地项目上传到Gitee仓库
1.右键点击文件,点击Git Bash Here,进入git窗口 2.初始化本地仓库 git init3.将本地仓库与远程仓库建立连接 git remote add origin 远程仓库地址远程仓库地址在gitee仓库复制即可 4.将远程仓库的文件拉到本地仓库中 git pull origin master5.将本地文件全部上传…...
linux环境安装docker
一、Docker是什么? 当我们开发一个应用程序时,通常需要配置和安装各种软件、库和依赖项。而这些环境配置可能会因为不同的操作系统或版本而存在差异,导致应用在不同环境中运行出现问题。 Docker就像是一个集装箱,可以将应用程序及其所有依…...
机器人技能学习-robosuite-0-入门介绍
文章目录 前言模块介绍实战案例1:从 demo 中创建自己的 env案例2:更换属于自己的物体 前言 资料太少、资料太少、资料太少,重要的事说三边,想根据自己实际场景自定义下机器人,结果发现无路可走,鉴于缺少参…...
【工具】tmux简单用法
tmux 是一个终端复用工具,允许你在单个终端窗口中运行多个终端会话,并在它们之间切换。它提供了分割窗格、多窗口和会话管理等功能,使得在终端中更加高效地工作。 以下是一些 tmux 的基本概念和简单应用: 会话 (Session): 一个 t…...
使用 C++/WinRT 的错误处理
本主题讨论了处理使用 C/WinRT 编程时出现的错误的策略。 更多常规信息和背景,请参阅错误和异常处理 (Modern C)。 避免捕获和抛出异常 建议继续编写异常安全代码,但最好尽量避免捕获和抛出异常。 如果没有异常处理程序,Windows 将自动生成错…...
计算机基础专升本笔记九-Windows7基础(一)Windows 7 介绍
计算机基础专升本笔记九-Windows7基础 一、Windows简介 Microsoft公司从1983年开始研制Windows系统,最初的研制目标是在MS-DOS的基础上提供一个多任务的图形用户界面。 1985年,第一个版本的Windows 1.0问世,它是一个具有图形用户界面的系…...
LeetCode1109. Corporate Flight Bookings
文章目录 一、题目二、题解 一、题目 There are n flights that are labeled from 1 to n. You are given an array of flight bookings bookings, where bookings[i] [firsti, lasti, seatsi] represents a booking for flights firsti through lasti (inclusive) with sea…...
视觉SLAM十四讲|【五】相机与IMU时间戳同步
视觉SLAM十四讲|【五】相机与IMU时间戳同步 相机成像方程 Z [ u v 1 ] [ f x 0 c x 0 f y c y 0 0 1 ] [ X Y Z ] K P Z \begin{bmatrix} u \\ v \\ 1 \end{bmatrix} \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix} \…...
js null和undefined的区别
null和undefined在JavaScript中都表示“无”的概念,但它们在使用和含义上有一些重要的区别。 含义: null 是一个表示“无”的对象,当转换为数值时结果为0。 undefined 是一个表示“缺少值”的原始值,当转换为数值时结果为NaN。…...
Arduino| IDE下载、安装和设置以及开发板的连接
IDE下载、安装和设置以及开发板的连接 IDE下载IDE安装IDE设置首选项——设置语言、字体、主题、地址等等开发板管理器——添加开发板 开发板的连接 IDE下载 第一步:进入Arduino官网https://www.arduino.cc。 第二步:选择导航栏的Software,然…...
Linux之Ubuntu环境Jenkins部署前端项目
今天分享Ubuntu环境Jenkins部署前端vue项目 一、插件安装 1、前端项目依赖nodejs,需要安装相关插件 点击插件管理,输入node模糊查询 选择NodeJS安装 安装成功 2、配置nodejs 点击后进入 点击新增 NodeJS 配置脚手架类型:如果不填 默认npm …...
QT下的几种实现modbus的库,记录
QModbus QT提供了一个名为QModbus的模块,可以实现Modbus的主机或从机功能 pro需要添加 QT += serialbus serialport相关头文件 #include <QModbusTcpClient> #include <QModbusDataUnit> 具体使用参考: https://blog.csdn.net/XCJandLL/article/details/1…...
HarmonyOS4.0系统性深入开发18公共事件简介
公共事件简介 HarmonyOS通过CES(Common Event Service,公共事件服务)为应用程序提供订阅、发布、退订公共事件的能力。 公共事件从系统角度可分为:系统公共事件和自定义公共事件。 系统公共事件:CES内部定义的公共事…...
华为路由器OSPF动态链路路由协议配置
R1配置 interface GigabitEthernet0/0/0ip address 10.1.12.1 255.255.255.252 interface LoopBack0ip address 1.1.1.1 255.255.255.255 ospf 1 router-id 1.1.1.1 area 0.0.0.0 network 1.1.1.1 0.0.0.0 network 10.1.12.0 0.0.0.3 R2配置 interface GigabitEthernet0/0/0i…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
