Redis Ordered Set

Redis 的有序集和(ordered set)同时具有"有序"和"集和"两种性质, 这种结构中每个元素都由一个成员和一个与成员相关联的分值组成, 其中成员与字符串方式存储, 而分值以64位双精度浮点数格式存储. 例如下面一个记录薪水的集和: 成员 分值 “perter” 3500 “bob” 3800 “jack” 4500 “tom” 5000 “mary” 5500 与集和一样, 有序集和中的元素都是唯一的, 同时, 成员将按照分值大小进行排序. 有序集和分值除了可以是数字外, 还可以是字符串 “+inf” 或者 “-inf”, 这两个特殊值分别表示无穷大和无穷小. 虽然有序集和的成员不可相同, 但是分值可以是相同的, 当两个或多个成员拥有相同的分值时,Redis 将按照这些成员在字典序中的大小对其进行排列. 有序集合是Redis提供的所有数据结构中最为灵活的一种, 它可以以多种不同的方式获取数据, 比如根据成员获取分值、根据分值获取成员、根据成员的排名获取成员、根据指定的分值范围获取多个成员等. ZADD: 添加或更新成员 ZADD sorted_set socre number [score number ...] 默认情况下, ZADD 命令将返回成功添加的新成员数量作为返回值, 对于更新操作会返回0(未添加新成员). 使用 XX | NX 选项来显示地指示命令 只更新 或 只添加操作 ZADD sorted [XX|NX] socre member [socre member ...] 若要返回所有被修改的成员数量(新添加 + 更新数量), 可使用 CH 选项 ZADD sorted_set [CH] socre number [score number ...] 复杂度: O(M * log(N)) 其中 M 为给定成员数量, N 为有序集和的成员数量 ...

August 30, 2025 · 4 min · 646 words · Starslayerx

Asyncio vs Gevents in Python

python 中 asyncio 和 gevent 是两种协程(在一个线程内实现并发)的实现, 这篇文章对比介绍这两者实现. 下面先介绍一下基础概念: Coroutines 协程 在 Python 中, 协程是可以暂停和继续运行的函数, 使得其是否适合并发编程. 定义使用 async def 语法, 协程运行编写非阻塞的操作. 在协程内, await 关键字用于暂停执行, 直到给定的任务完成, 从而运行其他协程在此其间并发运行. Event Loop 事件循环 事件循环是一种控制结构, 它不断地处理一系列事件, 处理任务并管理程序的执行流程. 等待事件发生, 处理后再等待下一个事件. 这种机制确保程序能够以高效有序的方式响应事件, 例如用户输入、计时器或者消息. 下面是事件循环如何管理协程: 任务提交: 当向事件循环提交一个协程时, 其被封装在一个 Task 对象中, 然后任务被安排在事件循环上运行. 内部队列: 事件循环使用几个内部数据结构来管理和调度这些任务 就绪队列 (Ready Queue): 包含可以立即运行的任务. I/O 选择器 (I/O Selector): 监控文件描述符, 并根据 I/O 准备情况调度任务 计划回调 (Scheduled Callbacks): 管理计划在一定延迟后运行的任务. 调度: 事件循环不断检查这些队列和数据结构, 以确定哪些任务已准备好执行. 然后它运行这些任务, 在遇到 await 语句时, 根据需要暂停和恢复它们. 并发管理: 通过交错执行多个协程, 事件循环无需多个线程即可实现并发. 在任何时候, 只有一个任务会运行, 但如果一个任务是 I/O 密集型的, 它会切换到另一个任务, 给人一种并行的错觉. ...

August 29, 2025 · 4 min · 694 words · Starslayerx

Prompt Organization

这篇文章旨在介绍 Python 中常用的提示词组织方式 f-string 使用 f 字符串填充变量得到提示词 def get_prompt(query: str) -> list[dict]: SYSTEM_PROMPT = f"""... ... 多行提示词, 也可以填充变量 """ USER_PROMPT = f"""INPUT: {query} .... """ return [ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": USER_PROMPT}, ] 这种方法实现简单, 速度快, 但是: 多行字符串由于填充变量的需要, 需写在函数内, 导致代码格式混乱 # 实际上, 多行字符串还可以这样实现, 但也不太时候提示词太多的时候, 但这样代码格式会更加优雅 system_prompt = ( f"你是一名{role}负责...\n" f"具体规则:\n" f"1. ...." f"2. ...." ) 上面这种方法会将多行字符串合并, 注意不要加逗号, 不然就变成元组了 通过代码构造提示词, 任何修改都需要修改代码, 扩展性差 string.Template 使用 Python 元素字符串模板 SYSTEM_PROMPT = string.Template("""你是一名$role 多行提示词... """) USER_PROMPT = string.Template("""INPUT: $query """) def get_prompt(role: str, query: str) -> list[dict]: system_prompt = SYSTEM_PROMPT.subtitute(role="助手") user_prompt = USER_PROMPT.subtitute(query="问题...") return [ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}, ] 使用模板字符串, 模板则不必写在函数内, 且模板字符串可以选择替换部分变量, 使用 .safe_substitute()方法传入一个字典, 例如 {"query": "问题..."}, 对没有传入的变量解析为 $var 对比 f-string, 模板字符串更加灵活, 且可以只传入部分值 ...

August 28, 2025 · 2 min · 305 words · Starslayerx

From Python to Go

From Python to Go: Why We Rewrote Our Ingest Pipeline at Telemetry Harbor 我们将 Telemetry Harbor 的摄取管道从 Python FastAPI 重写为 Go,原因是遇到了严重的性能瓶颈。迁移后,效率提升了 10 倍,数据完整性因严格类型检查而得到加强,系统也拥有了稳定、可扩展的高并发时间序列数据摄取基础。 背景:打造一个时间序列数据平台 Telemetry Harbor 源自我们在汽车行业积累的经验。几乎每个项目都要重复搭建相同的基础设施:数据库、后端、数据摄取管道、可视化界面。每次都要花费数周时间,这让我们萌生了打造一个开箱即用平台的想法。 当时的市场方案并不理想。InfluxDB 的商业化策略让许多关键特性被锁在付费墙后,版本迁移成本高且在大数据负载下表现不佳。TimescaleDB 与 ClickHouse 技术上更强大,但依旧需要用户自行构建后端与摄取管道。我们看到了缺口——需要一个极简、可靠、可直接使用的平台。 Python FastAPI:原型开发的正确选择 MVP 阶段,我们在开发速度与运行性能之间权衡。最终选择了 Python FastAPI,因为它允许我们: 快速验证市场假设 迅速收集客户反馈并迭代 在低成本下尝试多种方案 尽快上线以抢占市场 早期架构非常直接:HTTP API(避免防火墙问题)、Redis + RQ 队列、TimescaleDB。测试效果良好,但很快暴露了性能隐患——RQ 的同步处理方式无法支撑高吞吐场景。 性能瓶颈:Python 无法跟上增长 随着数据量上升,性能问题逐渐浮现: 空闲 CPU 占用:10% 中等负载:约 40% CPU 高负载:120–300% CPU(峰值 800%),频繁崩溃 问题不仅在于 RQ 的同步限制,而是整个 Python 架构在常规负载下都难以维持稳定。这迫使我们考虑全面重写。 迁移决策:为什么选择 Go? 我们评估了 Rust 和 Go: ...

August 27, 2025 · 1 min · 148 words · Starslayerx

Redis Set

Redis 的集和 set 键允许用户将任意多个不同的元素存储到集和中, 既可以是文本数据, 也可以是二进制数据. 其与列表有以下两个明显的区别: 列表可以存储重复元素, 而集和只存储非重复元素 列表以有序方式存储元素, 而集和则以无序方式存储元素 下面介绍结合键的各个命令 Set 集和 SADD: 将元素添加到集和 SADD set element [element ...] 返回成功添加的新元素数量作为返回值, 由于集和不存储相同元素, 所以会自动忽略重复的元素 SREM: 从集和中移出元素 SREM set element [element ...] 返回被移除的元素数量, 同样的, 不存在的元素会被忽略 SMOVE: 将元素从一个集和移动到另一个集和 SMOVE source target element 移动操作成功时返回1, 若不存在于源集和, 返回0. 如果 source 的元素不存在, 则返回0表示失败. 如果 target 的元素已存在, 则会覆盖该元素. 从结果来看, 并不会导致 target 中元素变化, 但是会导致 source 中的该元素消失. SMEMBERS: 获取集和包含的所有元素 SMEMBERS set 由于集和是无序的, 且 SMEMBERS 命令不会进行任何排序操作, 所以根据元素添加的顺序不同, 含相同元素的集和执行该命令结果可能不同. SCARD: 获取集和包含的元素数量 SCARD set SISMEMBER: 检查给定元素是否存在于集和 ...

August 26, 2025 · 4 min · 780 words · Starslayerx

Documenting REST APIs with OpenAPI

本章介绍如何使用 OpenAPI 来为 API 编写文档. OpenAPI 是描述 RESTful API 最流行的标准, 拥有丰富的生态系统, 可以用于测试、验证和可视化 API. 大多数编程语言都支持 OpenAPI 规范的库. OpenAPI 使用 JSON Schema 来描述 API 的结构和模型, 因此首先介绍 JSON Schema 的工作原理. JSON Schema 是一种用于定义 JSON 文档结构的规范, 包括文档中值的类型和格式. Using JSON Schema to model data 使用 JSON Schema 对数据建模 JSON Schema 是一种规范标准, 用于定义 JSON 文档的结构及其属性的类型和格式. JSON Schema 规范通常定义一个具有特定属性或特性的对象, 由键值对的关联数组表示, 如下面这样: { "status": { "type": "string" } } 在 JSON Schema 规范中, 每个属性都以键值对的形式出现, 其中值是该属性的描述符 一个属性最基本的描述符就是 type, 上面例子中, 指定类型为字符串 JSON Schema 支持以下基本数据类型: ...

August 25, 2025 · 9 min · 1727 words · Starslayerx

Redis List

List 列表 Redis 的列表是一种线性的有序结构, 可以按照元素被推入列表的顺序来存储元素, 这些元素即可以是文字顺序, 也可以是二进制顺序, 且元素可重复出现. LPUSH: 将元素推入列表左端 LPUSH list item [item item ...] LPUSH 命令会返回当前元素数量 RPUSH: 将元素推入列表右端 RPUSH list item [item item ...] LPUSHX, RPUSHX: 只对已存在的列表执行推入操作 上面两条命令, 在列表不存在的情况下, 会自动创建空列表, 并将元素推入列表中. 且上面命令每次只能推入一个元素 LPOP: 弹出列表最左端的元素, 并返回被移出的元素 POP list 空列表 POP 会返回空值 (nil) RPOP: 弹出列表最右端的元素 RPOP list RPOPLPUSH: 将列表右端弹出的元素推入列表左端 RPOPLPUSH source target source 和 target 可以是相同列表, 也可以是不同列表. 但不能为空列表, 否则会返回空(nil) 示例: 先入先出队列 许多电商网站都会在节日时推出一些秒杀活动, 这些活动会放出数量有限的商品供用户抢购, 秒杀系统的一个特点就是短时间内会有大量用户进行相同的购买操作, 如果使用事务或者锁去实现秒杀程序, 那么会因为锁和事务的重试性而导致性能低下, 并且由于重试的存在, 成功购买商品的用户可能并不是最早购买操作的用户, 因此这种秒杀系统并不公平. 解决方法之一就是把用户的购买操作都放入先进先出队列里面, 然后以队列的方式处理用户购买操作, 这样的程序就可以不使用锁或者事务实现秒杀系统, 且更加公平. ...

August 24, 2025 · 3 min · 489 words · Starslayerx

Rust Alternaitve Tools

常用工具的 rust 替代品. Introduction 在 Unix 生态中, 许多命令行工具都是用 C 编写的, 经过几十年的优化, 性能和稳定性都非常优秀. 然而, 近年来, Rust 以其安全性、内存管理优势和现代化开发体验, 成为系统级工具开发的理想选择. 首先更新 cargo, 不同系统都可以使用 cargo 安装, 当然也可以使用系统的包管理器安装 rustup update stable 有需要的话修改源, 一般在 ~/.cargo/config.toml, 下面是科大源 [source.crates-io] replace-with = 'ustc' [source.ustc] registry = "sparse+https://mirrors.ustc.edu.cn/crates.io-index/" [registries.ustc] index = "sparse+https://mirrors.ustc.edu.cn/crates.io-index/" Filesystem & Archiving 文件系统与归档 exa 替代 ls: 彩色支持 Git 状态的 ls 替代品 常用参数: -1: 一行显示一个文件 -l: 显示文件细节信息 -F: 在目录文件名末添加斜杠符号 -T: 树状显示 -R: 递归显示所有文件 --icons: 显示图标 zoxide 替代 cd: 基于访问频率的快速目录跳转工具 常用参数: z foo # 匹配 foo 的路径 z foo bar # 匹配 foo & bar 的路径 z - # 回到之前目录 zi foo # fzf File & Text Processing 文件与文本处理 bat 替代 cat: 具备语法高亮、行号显示、Git 集成等功能, 让查看文件内容更加美观 ripgrep 替代 grep: 使用 Rust 编写的极速文本搜索工具, 支持递归搜索、正则表达式、忽略规则(.gitignore)等 fd 替代 find: 提供简单直观的语法、更快的搜索性能, 并默认支持彩色输出和忽略 .gitignore 文件 System Monitoring & Management 系统监控与管理 bottom 替代 top / htop: 一个现代化的系统资源监控工具, 支持 CPU、内存、磁盘、网络等多种指标显示, 并提供交互式界面 procs 替代 ps: 更人性化的进程信息显示, 支持彩色输出、树状显示、搜索与过滤 Wrapping up Rust 的安全性和高性能使其成为编写现代 Linux 工具的理想选择. 这些替代品不仅提供了更好的用户体验, 还利用 Rust 的并发优势和零成本抽象提升了性能. 其他一些 rust 工具: ...

August 23, 2025 · 1 min · 160 words · Starslayerx

Tokei

Tokei 介绍 Tokei是一款 Rust 编写的开源工具, 用于统计项目代码行数, 支持上百种语言, 能够扫描整个代码库, 包括: 语言 文件数量 代码行数 注释行数 空行数 得益于 Rust 的高性能实现, Tokei 即使在超大规模代码库中也能保持极快的统计速度 (Rust 轮子真不错) 安装 brew install tokei 或者 cargo install tokei 使用 在项目根目录执行 tokei . 输出类似下面这样 =============================================================================== Language Files Lines Code Comments Blanks =============================================================================== Dockerfile 1 25 9 8 8 Python 52 2914 2372 96 446 TOML 1 65 58 0 7 YAML 2 49 45 0 4 ------------------------------------------------------------------------------- Markdown 1 194 0 158 36 |- BASH 1 13 13 0 0 (Total) 207 13 158 36 =============================================================================== Total 57 3247 2484 262 501 ===============================================================================

August 22, 2025 · 1 min · 93 words · Starslayerx

Redis Hash

散列 Redis 散列键 hash key 会将一个键和一个散列在数据库里关联起来, 散列中可以存任意多个字段 field. 与字符串一样, 散列字段和值既可以是文本数据, 也可以是二进制数据. HSET: 为字段设置值 HEST hash field value 若已给定的字段是否已经存在与散列中, 该设置为一次更新操作, 覆盖旧值后返回0. 相反, 则为一次创建操作, 命令将在散列里面关联起给定的字段和值, 然后返回1. HSETNX: 只在字段不存在的情况下设置值 HSETNX hash field value HSETNX 命令在字段不存在且成功设置值时, 返回1. 字段已存在并设置值未成功时, 返回0. HGET: 获取字段的值 HGET hash field 若查找的不存在的散列或字段, 则会返回空(nil) 示例: 短网址生成 为了给用户提供更多空间, 并记录用户在网站上的链接点击行为, 大部分社交网站都会将用户输入的网址转换为短网址. 当用户点击段网址时, 后台就会进行数据统计, 并引导用户跳转到原地址. 创建短网址本质上就是, 要创建出短网址ID与目标网址之间的映射, 并让用户访问短网址时, 根据短网址的ID映射记录中找出与之相对应的目标网址. 短网址 ID 目标网址 RqRRz8n http://redisdoc.com/geo/index.html RUwtQBx http://item.jd.com/117910607.html HINCRBY: 对字段存储的整数值执行加法或减法操作 HINCRBY hash field increment 与字符串 INCRBY 命令一样, 如果散列字段里面存储着能够被 Redis 解释为整数的数字, 那么用户就可以使用 HINCRBY 命令为该字段的值加上指定的整数增量. 该命令执行成功后, 将返回字段当前的值为命令的结果. 若要执行减法操作, increment 传入负数即可. ...

August 21, 2025 · 3 min · 557 words · Starslayerx