【Go | 从0实现简单分布式缓存】-2:HTTP服务端与一致性哈希
本文目录
- 一、回顾
- 1.1 复习接口
- 二、http标准库
- 三、实现HTTP服务端
- 四、一致性哈希
本文为极客兔兔“动手写分布式缓存GeeCache”学习笔记。
一、回顾
昨天已经开发了一部分项目,我们先来看看项目结构。
分布式缓存需要实现节点间通信,建立基于 HTTP 的通信机制是比较常见和简单的做法。如果一个节点启动了 HTTP 服务,那么这个节点就可以被其他节点访问。
所以现在需要为单机节点搭建 HTTP Server。
1.1 复习接口
接口是一个类型,它定义了一组方法签名(方法名和参数列表)。一个类型只要实现了接口中定义的所有方法,就自动实现了该接口。
type 接口名称 interface {方法1(参数列表) 返回值方法2(参数列表) 返回值...
}
例如,http.Handler
是Go标准库中定义的一个接口:
type Handler interface {ServeHTTP(w http.ResponseWriter, r *http.Request)
}
这个接口定义了一个方法 ServeHTTP,任何类型只要实现了这个方法,就自动实现了 http.Handler 接口。
在Go中,实现接口不需要显式声明。只要一个类型提供了接口中定义的所有方法,它就隐式地实现了该接口。
假设我们定义一个接口 Greeter,它有一个方法 Greet:
type Greeter interface {Greet() string
}
接下来定义一个类型 Person,并为它实现 Greet 方法:
type Person struct {Name string
}func (p Person) Greet() string {return "Hello, my name is " + p.Name
}
Person 类型定义了一个方法 Greet,其签名与 Greeter 接口中的方法一致。所以Person 类型自动实现了 Greeter 接口。
我们可以将 Person 类型的变量赋值给 Greeter 类型的变量,并调用接口方法:
func main() {p := Person{Name: "Alice"}var g Greeter = pfmt.Println(g.Greet()) // 输出: Hello, my name is Alice
}
类型断言用于检查一个接口变量是否实现了某个具体类型,并获取该具体类型的值:
var i interface{} = "Hello"
if str, ok := i.(string); ok {fmt.Println("It's a string:", str)
} else {fmt.Println("It's not a string")
}
二、http标准库
复习完上面的接口,我们来看看怎么实现go提供的http标准库。
w http.ResponseWriter
:用于向客户端发送HTTP响应。r *http.Request
:包含客户端请求的所有信息。
type Handler interface {ServeHTTP(w http.ResponseWriter, r *http.Request)
}
代码中type server int
,是一个基于 int 的新类型,但类型本身并不重要,重要的是它通过方法实现了接口。接下来,为 server 类型定义一个方法。
server 类型定义了一个方法 ServeHTTP,其签名与 http.Handler 接口中的方法完全一致。因此,server 类型自动实现了 http.Handler 接口。
func (h *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {log.Println(r.URL.Path)w.Write([]byte("Hello World!"))
}
http.ListenAndServe()
函数需要两个参数,分别是addr地址,还有handler处理器。
由于 server 实现了 ServeHTTP 方法,&s 满足 http.Handler 接口的要求。
通过将 server 类型的指针传递给 http.ListenAndServe,我们可以将其作为HTTP处理器使用。
所以完整的一个简单HTTP服务端代码如下。
package Geecacheimport ("log""net/http"
)type server int// ServeHTTP 是 http.Handler 接口的唯一方法。通过实现这个方法,server 类型的实例可以作为HTTP处理器。
func (h *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {log.Println(r.URL.Path) // 将请求的路径记录到日志中。w.Write([]byte("Hello World!")) //向客户端发送响应。
}func main() {var s server//启动一个HTTP服务器,监听 localhost 上的 9999 端口。//第二个参数 &s 是一个 server 类型的指针,表示将 s 作为HTTP处理器。//由于 server 类型实现了 ServeHTTP 方法,因此它满足 http.Handler 接口。http.ListenAndServe("localhost:9999", &s)
}
在Go中,接口变量存储了两个信息:
动态类型:变量的实际类型(在这里是 *server)。
动态值:变量的实际值(在这里是 &s)。
当调用接口方法时,Go运行时会根据动态类型找到对应的方法实现,并执行它。这种机制使得接口非常灵活,且运行时可以动态绑定方法。
三、实现HTTP服务端
项目结构如上图所示,接下来我们在main.go
中写测试代码。
跟昨天一样,使用 map 模拟了数据源 db。创建一个名为 scores 的 Group,若缓存为空,回调函数会从 db 中获取数据并返回。使用 http.ListenAndServe 在 9999 端口启动了 HTTP 服务。
需要注意的是main.go 和 geecache/ 在同级目录,但 go modules 不再支持 import <相对路径>,相对路径需要在 go.mod 中声明:
require geecache v0.0.0
replace geecache => ./geecache
package main/*
$ curl http://localhost:9999/_geecache/scores/Tom
630$ curl http://localhost:9999/_geecache/scores/kkk
kkk not exist
*/import ("fmt""geecache""log""net/http"
)// 模拟数据库,db
var db = map[string]string{"Tom": "630","Jack": "589","Sam": "567",
}// 回调函数是一个通过参数传递给另一个函数的函数,并在某个事件发生时被调用。在这段代码中:
// 匿名函数被传递给geecache.NewGroup作为GetterFunc的参数。
// 当缓存中没有找到对应的key时,geecache会调用这个函数来从底层存储中获取数据。// geecache.GetterFunc:将一个匿名函数转换为Getter接口的实现。
func main() {geecache.NewGroup("scores", 2<<10, geecache.GetterFunc(func(key string) ([]byte, error) {log.Println("[SlowDB] search key", key)// 回调函数,当调用g.getter.Get(key) 就会从下面的代码运行从db中去取数据了if v, ok := db[key]; ok {return []byte(v), nil}return nil, fmt.Errorf("%s not exist", key)}))addr := "localhost:9999"peers := geecache.NewHTTPPool(addr)log.Println("geecache is running at", addr)log.Fatal(http.ListenAndServe(addr, peers))
}
然后做一些简单的测试,可以看到对应的输出如下。
四、一致性哈希
对于分布式缓存来说,当一个节点接收到请求,如果该节点并没有存储缓存值,那么它面临的难题是,从谁那获取数据?自己,还是节点1, 2, 3, 4… 。假设包括自己在内一共有 10 个节点,当一个节点接收到请求时,随机选择一个节点,由该节点从数据源获取数据。
假设第一次随机选取了节点 1 ,节点 1 从数据源获取到数据的同时缓存该数据;那第二次,只有 1/10 的可能性再次选择节点 1, 有 9/10 的概率选择了其他节点,如果选择了其他节点,就意味着需要再一次从数据源获取数据,一般来说,这个操作是很耗时的。这样做,一是缓存效率低,二是各个节点上存储着相同的数据,浪费了大量的存储空间。
那有什么办法,对于给定的 key,每一次都选择同一个节点呢?使用 hash 算法也能够做到这一点。那把 key 的每一个字符的 ASCII 码加起来,再除以 10 取余数可以吗?当然可以,这可以认为是自定义的 hash 算法。
但是这会导致另一个问题,就是缓存雪崩
,简单求取 Hash 值解决了缓存性能的问题,但是没有考虑节点数量变化的场景。假设移除了其中一台节点,只剩下 9 个,那么之前 hash(key) % 10 变成了 hash(key) % 9,也就意味着几乎缓存值对应的节点都发生了改变。即几乎所有的缓存值都失效了。
节点在接收到对应的请求时,均需要重新去数据源获取数据,容易引起 缓存雪崩。
缓存雪崩:缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。常因为缓存服务器宕机,或缓存设置了相同的过期时间引起。
而一致性哈希算法可以解决这个问题。
一致性哈希算法将 key 映射到 2^32 的空间中,将这个数字首尾相连,形成一个环。
计算节点/机器(通常使用节点的名称、编号和 IP 地址)的哈希值,放置在环上。
计算 key 的哈希值,放置在环上,顺时针寻找到的第一个节点,就是应选取的节点/机器。
环上有 peer2,peer4,peer6 三个节点,key11,key2,key27 均映射到 peer2,key23 映射到 peer4。此时,如果新增节点/机器 peer8,假设它新增位置如图所示,那么只有 key27 从 peer2 调整到 peer8,其余的映射均没有发生改变。
也就是说,一致性哈希算法,在新增/删除节点时,只需要重新定位该节点附近的一小部分数据,而不需要重新定位所有的节点,这就解决了上述的问题。
但是相对的,也会有新问题,那就是如果服务器的节点过少,容易引起 key 的倾斜。例如上面例子中的 peer2,peer4,peer6 分布在环的上半部分,下半部分是空的。那么映射到环下半部分的 key 都会被分配给 peer2,key 过度向 peer2 倾斜,缓存节点间负载不均。
为了解决这个问题,引入了虚拟节点的概念,一个真实节点对应多个虚拟节点。
假设 1 个真实节点对应 3 个虚拟节点,那么 peer1 对应的虚拟节点是 peer1-1、 peer1-2、 peer1-3(通常以添加编号的方式实现),其余节点也以相同的方式操作。
虚拟节点扩充了节点的数量,解决了节点较少的情况下数据容易倾斜的问题。而且代价非常小,只需要增加一个字典(map)维护真实节点与虚拟节点的映射关系即可。
然后我们可以试着来实现一致性哈希
算法,新建consistenthash
文件。
package consistenthashimport ("hash/crc32""sort""strconv"
)// Hash maps bytes to uint32
type Hash func(data []byte) uint32// Map constains all hashed keys
type Map struct {hash Hashreplicas intkeys []int // SortedhashMap map[int]string
}// New creates a Map instance
func New(replicas int, fn Hash) *Map {m := &Map{replicas: replicas,hash: fn,hashMap: make(map[int]string),}if m.hash == nil {m.hash = crc32.ChecksumIEEE}return m
}// Add adds some keys to the hash.
func (m *Map) Add(keys ...string) {for _, key := range keys {for i := 0; i < m.replicas; i++ {hash := int(m.hash([]byte(strconv.Itoa(i) + key)))m.keys = append(m.keys, hash)m.hashMap[hash] = key}}sort.Ints(m.keys)
}// Get gets the closest item in the hash to the provided key.
func (m *Map) Get(key string) string {if len(m.keys) == 0 {return ""}hash := int(m.hash([]byte(key)))// Binary search for appropriate replica.idx := sort.Search(len(m.keys), func(i int) bool {return m.keys[i] >= hash})return m.hashMap[m.keys[idx%len(m.keys)]]
}
定义函数类型 Hash,采取依赖注入的方式,允许用于替换成自定义的 Hash 函数,也方便测试时替换,默认为 crc32.ChecksumIEEE 算法。
Map 是一致性哈希算法的主数据结构,包含 4 个成员变量:Hash 函数 hash;虚拟节点倍数 replicas;哈希环 keys;虚拟节点与真实节点的映射表 hashMap,键是虚拟节点的哈希值,值是真实节点的名称。
构造函数 New() 允许自定义虚拟节点倍数和 Hash 函数。
接下来可以进行对应测试。
package consistenthashimport ("strconv""testing"
)func TestHashing(t *testing.T) {hash := New(3, func(key []byte) uint32 {i, _ := strconv.Atoi(string(key))return uint32(i)})// Given the above hash function, this will give replicas with "hashes":// 2, 4, 6, 12, 14, 16, 22, 24, 26hash.Add("6", "4", "2")testCases := map[string]string{"2": "2","11": "2","23": "4","27": "2",}for k, v := range testCases {if hash.Get(k) != v {t.Errorf("Asking for %s, should have yielded %s", k, v)}}// Adds 8, 18, 28hash.Add("8")// 27 should now map to 8.testCases["27"] = "8"for k, v := range testCases {if hash.Get(k) != v {t.Errorf("Asking for %s, should have yielded %s", k, v)}}}
一开始,有 2/4/6 三个真实节点,对应的虚拟节点的哈希值是 02/12/22、04/14/24、06/16/26。
那么用例 2/11/23/27 选择的虚拟节点分别是 02/12/24/02,也就是真实节点 2/2/4/2。
添加一个真实节点 8,对应虚拟节点的哈希值是 08/18/28,此时,用例 27 对应的虚拟节点从 02 变更为 28,即真实节点 8。
相关文章:
【Go | 从0实现简单分布式缓存】-2:HTTP服务端与一致性哈希
本文目录 一、回顾1.1 复习接口 二、http标准库三、实现HTTP服务端四、一致性哈希 本文为极客兔兔“动手写分布式缓存GeeCache”学习笔记。 一、回顾 昨天已经开发了一部分项目,我们先来看看项目结构。 分布式缓存需要实现节点间通信,建立基于 HTTP 的…...
STM32 低功耗模式
目录 背景 低功耗模式 睡眠模式 进入睡眠模式 退出睡眠模式 停止模式 进入停止模式 退出停止模式 待机模式 进入待机模式 退出待机模式 程序 睡眠模式 休眠模式配置 进入休眠模式 退出睡眠模式 停止模式 停止模式配置 进入停止模式 退出停止模式 待机模式…...
AI 百炼成神:逻辑回归, 垃圾邮件分类
第二个项目:逻辑回归垃圾邮件分类 项目代码下载地址:https://download.csdn.net/download/m0_56366541/90398247 项目目标 学习逻辑回归的基本概念。使用逻辑回归算法来实现垃圾邮件的分类。理解如何处理文本数据以及如何评估分类模型的性能。项目步骤 准备数据集 我们将使…...
#渗透测试#批量漏洞挖掘#Apache Log4j反序列化命令执行漏洞
免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停止本文章读。 目录 Apache Log4j反序列化命令执行漏洞 一、…...
Docker__持续更新......
Docker 1. 基本知识1.1 为什么有Docker?1.2 Docker架构与容器化 画图解释 画图解释2. 项目实战 1. 基本知识 1.1 为什么有Docker? 用一行命令跨平台安装项目,在不同平台上运行项目。把项目打包分享运行应用。 1.2 Docker架构与容器化 准备机器,在机…...
什么是语料清洗、预训练、指令微调、强化学习、内容安全; 什么是megatron,deepspeed,vllm推理加速框架
什么是语料清洗、预训练、指令微调、强化学习、内容安全 目录 什么是语料清洗、预训练、指令微调、强化学习、内容安全语料清洗预训练指令微调强化学习内容安全什么是megatron,deepspeed,vllm推理加速框架语料清洗 语料清洗是对原始文本数据进行处理的过程,旨在去除数据中的…...
Ubuntu虚拟机NDK编译ffmpeg
目录 一、ffmpeg源码下载1、安装git(用于下载ffmpeg源码)2、创建源码目录,下载ffmpeg源码 二、下载ubuntu对应的NDK,并解压到opt下1、下载并解压2、配置 ~/.bashrc 三、源码编译、1、创建编译脚本2、脚本文件内容3、设置可执行权限并运行4、编译的结果在…...
SQLAlchemyError: A transaction is already begun on this Session.
资料 sqlalchemy 事务 - 简书 在 SQLAlchemy 中,事务是通过会话来管理的。当你开始一个事务(例如使用 async with db.begin()),它会开启一个新的事务,并在事务块结束时自动提交或回滚。如果在同一个会话中,…...
STM32 HAL库USART串口DMA IDLE中断编程:避坑指南
HAL_UART_Receive接收最容易丢数据了,STM32 HAL库UART查询方式实例 可以考虑用中断来实现,但是HAL_UART_Receive_IT还不能直接用,容易数据丢失,实际工作中不会这样用,STM32 HAL库USART串口中断编程:演示数据丢失, 需要在此基础优化一下. STM32F103 HAL库USART串口…...
打造一个有点好看的 uniapp 网络测速软件
大家好,我是一名前端小白。今天想和分享一个有点好看的网络测速 uniapp 组件的实现过程。这个组件不仅外观精美,而且具有完整的功能性,是一个非常适合学习和实践的案例。 设计理念 在开始coding之前,先聊聊设计理念。一个好的测…...
DeepSeek AI 视频创作完整指南:从注册到制作
DeepSeek AI 视频创作完整指南:从注册到制作 前言 DeepSeek作为国产AI的新星,不仅在代码能力上表现出色,在创意内容生成方面同样令人惊艳。本教程将带您从注册到实操,完整体验DeepSeek的强大功能。 第一步:获取Deep…...
DeepSeek学术指南:DeepSeek在学术翻译改写能力应用操作案例!
DeepSeek:助力学术研究的智能工具 DeepSeek作为一种先进的智能工具,为学术研究提供了强大的支持。它不仅能够处理复杂的学术文本,还能在翻译和润色方面表现出色,极大地提高了学术写作的效率和质量。通过其强大的语言处理能力&…...
栈回溯基础
指令集区分 thumb指令集 长度:thumb指令通常是 16 位。特点:thumb 指令集是为了压缩指令集长度减少程序占用空间。对齐方式:2字节对齐,存放 thumb 指令的地址一般会被1,设置为奇数,用于表示地址上存放的是…...
JavaScript系列(76)--浏览器API深入
JavaScript浏览器API深入 🌐 浏览器提供了丰富的API,使JavaScript能够与浏览器环境进行交互。本文将深入探讨常用的浏览器API、最佳实践和性能优化技巧。 核心浏览器API 🌟 💡 小知识:浏览器API是连接JavaScript与浏…...
计算机网络(3)TCP格式/连接
1、TCP三大特点:面向连接、可靠、基于字节流 2、如何唯一确定一个TCP连接?TCP四元组:源地址、源端口、目的地址、目的端口 源地址和目标地址的字段(32 位)是在 IP 头部中,作用是通过 IP 协议发送报文给对方主机源端口和目标端口…...
下载安装运行测试开源vision-language-action(VLA)模型OpenVLA
1. 安装 项目官网OpenVLA 首先按照官网提示的以下代码,执行创建环境->安装最小依赖->git克隆项目等 # Create and activate conda environment conda create -n openvla python3.10 -y conda activate openvla# Install PyTorch. Below is a sample comma…...
3D与2D机器视觉机械臂引导的区别
3D与2D机器视觉在机械臂引导中的主要区别如下: 数据维度 2D视觉:仅处理平面图像,提供X、Y坐标信息,无法获取深度(Z轴)数据。 3D视觉:处理三维空间数据,提供X、Y、Z坐标及物体的姿态…...
网站搭建基本流程
需求分析: 实现网站搭建的过程:首先进行网站的需求性分析 网站可分为前台系统和后台系统,由不同的功能拆分为不同的模块 如下是一个电商网站可以拆分出的模块: 在编写代码前,我们要先对网站进行架构,通过…...
SpringBoot启动时报错:cannot use an unresolved DNS server address: I:53
报错如下: 2025-02-17 13:59:41.374 [main] ERROR org.springframework.boot.SpringApplication:835 - Application run failed org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name mySwaggerResourceProvider def…...
Ollama命令使用指南
Ollama 命令使用指南 Ollama 命令使用指南1. Ollama 命令概览2. Ollama 命令详解2.1 启动 Ollama2.2 创建模型2.3 查看模型信息2.4 运行模型2.5 停止运行的模型2.6 从注册表拉取模型2.7 推送模型到注册表2.8 列出本地模型2.9 查看正在运行的模型2.10 复制模型2.11 删除模型 3. …...
每日一题——将数字字符串转化为IP地址
将数字字符串转化为IP地址 题目描述解题思路回溯法步骤分解 代码实现全局变量有效性验证函数回溯函数主函数完整代码 复杂度分析关键点说明总结 这题难度还挺大的,整体上实现并不容易。建议参考视频 和https://programmercarl.com/0093.%E5%A4%8D%E5%8E%9FIP%E5%9C%…...
2013年下半年软件设计师上午题考察知识点及其详细解释(附真题及答案解析)
以下是2013年下半年软件设计师上午题的所有题目(从第1题到第75题)的总结,按顺序列出每道题目的考察知识点及其详细解释,供考生背诵记忆: 1. Cache与主存的地址映像 知识点:存储管理解释:Cache与…...
实现可拖拽的 Ant Design Modal 并保持下层 HTML 可操作性
前言 在开发复杂的前端界面时,我们常常需要一个可拖拽的弹窗(Modal),同时又希望用户能够在弹窗打开的情况下操作下层的内容。Ant Design 的 Modal 组件提供了强大的功能,但默认情况下,弹窗会覆盖整个页面&…...
unity学习43:子状态机 sub-state machine
目录 1sub-state machine子状态机 1.1 创建 sub-state machine 1.2 sub-state machine 内容 1.3 子状态机的应用 2 子状态机不同于blend tree的嵌套 3 应用例子:若角色拿不同武器的动画设计,可以使用2种方法 3.1 在1个图层layer里,使用…...
HTML之JavaScript DOM(document)编程处理事件
HTML之JavaScript DOM(document)编程处理事件 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"…...
线性模型 - Logistic 回归
Logistic 回归(Logistic Regression,LR)是一种常用的处理二分类问题的 线性模型。 Logistic 回归是一种用于二分类问题的统计模型,它通过将输入特征的线性组合映射到一个概率值来进行分类决策。 Logistic回归是机器学习中最经典的分类算法之一…...
分割 学习笔记cvpr2024
目录 LiteMedSam 模型37m LightM-Unet 500 str 依赖项: MLWnet 73 star memsam 340M 126 star LiteMedSam 模型37m https://github.com/bowang-lab/MedSAM/blob/LiteMedSAM/README.md LightM-Unet 500 str https://github.com/MrBlankness/LightM-UNet/blob model = Li…...
ShenNiusModularity项目源码学习(9:项目结构)
ShenNiusModularity源码主要有11个project(其实还有officialweb、test两个文件夹,大致有4、5个project,但看着跟主要项目代码没太大关系,暂时不管),这11个project的依赖关系如下图所示,其中最下…...
【复现DeepSeek-R1之Open R1实战】系列6:GRPO源码逐行深度解析(上)
目录 4 GRPO源码分析4.1 数据类 GRPOScriptArguments4.2 系统提示字符串 SYSTEM_PROMPT4.3 奖励函数4.3.1 accuracy_reward函数4.3.2 verify函数4.3.3 format_reward函数 4.4 将数据集格式化为对话形式4.5 初始化GRPO Trainer 【复现DeepSeek-R1之Open R1实战】系列3࿱…...
【LangChain实践开发】如何对大模型I/O封装?
LangChain 的核心组件 模型 I/O 封装 LLMs:大语言模型Chat Models:一般基于 LLMs,但按对话结构重新封装PromptTemple:提示词模板OutputParser:解析输出 数据连接封装 Document Loaders:各种格式文件的加载…...
LangChain4j
LangChain4j 是一个基于 Java 的框架,旨在简化与大型语言模型(LLMs)的集成和应用开发。它类似于 Python 的 LangChain 框架,但专为 Java 开发者设计,提供了构建基于 LLM 的应用程序所需的工具和组件。 主要功能 LLM …...
如何系统成为高级Qt工程师?
要系统性地成为高级Qt工程师,需要从基础到进阶逐步构建知识体系,并结合实战经验、源码分析和架构设计能力的提升。以下是分阶段的系统性学习路径和建议: 一、夯实基础阶段 C++深度掌握 精通C++11/14/17特性(智能指针、lambda、移动语义等)理解面向对象设计、设计模式(如观…...
LLM 架构
LLM 分类 : 自编码模型 (encoder) : 代表模型 : BERT自回归模型 (decoder) : 代表模型 : GPT序列到序列模型 (encoder-decoder) : 代表模型 : T5 自编码模型 (AutoEncoder model , AE) 代表模型 : BERT (Bidirectional Encoder Representation from Transformers)特点 : Enc…...
MVTEC数据集笔记
前言 网上的博客只有从论文里摘出的介绍,没有数据集文件详细的样子,下载数据集之后,对数据集具体的构成做一个补充的笔记。 下载链接:https://ai-studio-online.bj.bcebos.com/v1/7d4a3cf558254bbaaf4778ea336cb14ed8bbb96a7f2a…...
[算法学习笔记]1. 枚举与暴力
一、枚举算法 定义 枚举是基于已有知识来猜测答案的问题求解策略。即在已知可能答案的范围内,通过逐一尝试寻找符合条件的解。 2. 核心思想 穷举验证:对可能答案集合中的每一个元素进行尝试终止条件:找到满足条件的解,或遍历完…...
javacv将mp4视频切分为m3u8视频并播放
学习链接 ffmpeg-demo 当前对应的 gitee代码 Spring boot视频播放(解决MP4大文件无法播放),整合ffmpeg,用m3u8切片播放。 springboot 通过javaCV 实现mp4转m3u8 上传oss 如何保护会员或付费视频?优酷是怎么做的? - HLS 流媒体加密 ffmpe…...
docker 进阶命令(基于Ubuntu)
数据卷 Volume: 目录映射, 目录挂载 匿名绑定: 匿名绑定的 volume 在容器删除的时候, 数据卷也会被删除, 匿名绑定是不能做到持久化的, 地址一般是 /var/lib/docker/volumes/xxxxx/_data 绑定卷时修改宿主机的目录或文件, 容器内的数据也会同步修改, 反之亦然 # 查看所有 vo…...
鸿蒙(HarmonyOS)开发学习路线指南:从零到实战
随着鸿蒙生态的快速发展,HarmonyOS 已成为物联网时代的重要开发平台。其分布式架构和“一次开发、多端部署”的理念吸引了大量开发者。本文将从零开始梳理鸿蒙开发的学习路径,帮助开发者高效掌握核心技能。 一、学习路线概览 总目标:掌握鸿蒙…...
小白win10安装并配置yt-dlp
需要yt-dlp和ffmpeg 注意存放路径最好都是全英文 win10安装并配置yt-dlp 一、下载1.下载yt-dlp2. fffmpeg下载 二、配置环境三、cmd操作四、yt-dlp下视频操作 一、下载 1.下载yt-dlp yt-dlp地址 找到win的压缩包点下载,并解压 2. fffmpeg下载 ffmpeg官方下载 …...
CUBEAI详细使用教程(STM32运行神经网络)---以手写识别为例
系列文章目录 文章目录 系列文章目录前言一、CUBEMX配置步骤二、模型结构及模型存储方式三、常用API函数1.ai_(name)_create()2.ai_(name)_init3.ai_(name)_create_and_init()3.ai_(name)_run()官方提供的示例代码 四、如何获取官方开发文档五、手写识别案例 前言 实验效果&am…...
[NOIP 1998 提高组] 拼数
https://www.luogu.com.cn/problem/P1012 将每个数用字符串的形式读进来,对于任意两个数 x x x, y y y,如果 x y > y x xy>yx xy>yx,对最后的答案来说, x x x一定排在 y y y的前面。 简单证明:假设最后的…...
PHP Web 开发基础
PHP 学习资料 PHP 学习资料 PHP 学习资料 在 PHP Web 开发领域,掌握一些基础概念和技术是构建功能强大、用户体验良好的 Web 应用的基石。接下来,我们将深入探讨 HTTP 协议、表单处理、Cookie 和 Session 的管理、URL 处理等关键内容。 一、HTTP 协议…...
MME-CoT:专为评估大型多模态模型CoT推理能力的基准测试。涵盖了数学、科学、OCR、逻辑、时空和一般场景6个领域。
2025-02-09 ,由CUHK MMLab、CUHK MulLab、字节跳动、、东北大学等机构联合发布MME-CoT数据集,该数据集目的评估大型多模态模型(LMMs)中的思维链(CoT)推理能力,涵盖数学、科学、OCR、逻辑、时空和…...
HDFS应用-后端存储cephfs-java-API
HDFS(Hadoop Distribute FileSystem)是一个适合运行在通用硬件之上,具备高度容错特性,支持高吞吐量数据访问的分布式文件系统,非常适合大规模数据集应用。 HDFS适用于如下场景: • 处理海量数据(TB或PB级别以上) • 需要很高的吞吐量 • 需要高可靠性 • 需要很好的可扩…...
A与B组件自动对齐与组装,无映射直接补偿。
网上针对组装的从视觉到控制动作,要不就是收费,要不就是简单介绍。这么详细的比较难找~ 手下留情,不喜勿喷! Show time~ 分步解决方案: 标定阶段(Calibration) 9点张氏标定(每个位置A1、A2、B1、B2): 使用机械手在相机视野内沿Z字形路径移动,覆盖9个点(XY方…...
SQL知识体系
SQL复习 MySQL SQL介绍 SQL SQL的全拼是什么? SQL全拼:Structured Query Language,也叫结构化查询语言。 SQL92和SQL99有什么区别呢? SQL92和SQL99分别代表了92年和99年颁布的SQL标准。 在 SQL92 中采用(ÿ…...
编译安装php
前置准备 这里的可能不全,每个人安装的模块不一致,依赖也不不相同,按实际情况调整 yum install libxml2 -y yum install libxml2-devel -y yum install openssl-devel -y yum install sqlite-devel -y yum install libcurl-devel -yyum ins…...
【分果果——DP(困难)】
题目 分析 分果果题解参考,下面是补充https://blog.csdn.net/AC__dream/article/details/129431299 关于状态 设f[i][j][k]表示第i个人取到的最后一个糖果编号是j,第i-1个人取到的最后一个糖果编号小于等于k时的最大重量的最小值 关于转移方程 关于 j …...
利用ffplay播放udp组播视频流
ffplay -fs -fflags nobuffer -flags low_delay -analyzeduration 0 -probesize 32 -framedrop -sync ext -strict experimental udp://224.1.1.1:5001 -fs : 全屏显示 -fflags nobuffer : 禁用输入缓冲(减少100-200ms缓冲延迟) -an…...
C++中变量与容器的默认初始化:0的奥秘
在C编程的世界里,初始化是一个至关重要的概念。它决定了变量或容器在程序开始执行时的初始状态。然而,对于不同的数据类型和容器,C标准对于默认初始化的行为有着不同的规定。本文将深入探讨C中变量与容器的默认初始化规则,特别是关…...